/* * Copyright (c) 2024-2025 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 present_timing.hpp * * @brief Contains the implentation for the VK_EXT_present_timing extension. * */ #pragma once #include #include #include #include #include #include "wsi_extension.hpp" #if VULKAN_WSI_LAYER_EXPERIMENTAL namespace wsi { /** * @brief Swapchain presentation entry * * This structure is used to keep the parameters for the swapchain presentation entry. * */ struct swapchain_presentation_entry { /** * Whether this entry is an outstanding result or not. */ bool is_outstanding{ false }; /** * The present id. */ uint64_t present_id{ 0 }; }; /** * @brief Timings queue * * This structure is used to keep the parameters related to the presentation timing queue. * */ struct timings_queue { timings_queue(const util::allocator &allocator) : m_timings(allocator) { } util::vector m_timings; }; // Predefined struct for calibrated time struct swapchain_calibrated_time { VkTimeDomainKHR time_domain; uint64_t offset; }; // Base struct for swapchain time domain class swapchain_time_domain { public: swapchain_time_domain(VkPresentStageFlagsEXT presentStages) : m_present_stages(presentStages) { } virtual ~swapchain_time_domain() = default; virtual swapchain_calibrated_time calibrate() = 0; VkPresentStageFlagsEXT get_present_stages() { return m_present_stages; } private: VkPresentStageFlagsEXT m_present_stages; }; class vulkan_time_domain : public swapchain_time_domain { public: vulkan_time_domain(VkPresentStageFlagsEXT presentStages, VkTimeDomainKHR time_domain) : swapchain_time_domain(presentStages) , m_time_domain(time_domain) { } /* The calibrate function should return a Vulkan time domain + an offset.*/ swapchain_calibrated_time calibrate() override { return { m_time_domain, 0 }; } private: VkTimeDomainKHR m_time_domain; }; /** * @brief Class holding time domains for a swapchain * */ class swapchain_time_domains { public: swapchain_time_domains(const util::allocator &allocator) : m_time_domains(allocator) { } /** * @brief Add new time domain * * @param time_domain Time domain to add * @return true Time domain has been added. * @return false Time domain has not been added due to an issue. */ bool add_time_domain(util::unique_ptr time_domain); VkResult calibrate(VkPresentStageFlagBitsEXT presentStages, swapchain_calibrated_time *calibrated_time); /** * @brief Get swapchain time domain properties. * * @param pSwapchainTimeDomainProperties time domain struct to be set * @param pTimeDomainsCounter size of the pSwapchainTimeDomainProperties * * @return Returns VK_SUCCESS on success, otherwise an appropriate error code. */ VkResult get_swapchain_time_domain_properties(VkSwapchainTimeDomainPropertiesEXT *pSwapchainTimeDomainProperties, uint64_t *pTimeDomainsCounter); private: util::vector> m_time_domains; }; /** * @brief Present timing extension class * * This class implements or act as a base class for the present timing extension * features. */ class wsi_ext_present_timing : public wsi_ext { public: /** * @brief The name of the extension. */ WSI_DEFINE_EXTENSION(VK_EXT_PRESENT_TIMING_EXTENSION_NAME); template static util::unique_ptr create(const util::allocator &allocator, std::array, N> &domains) { auto present_timing = allocator.make_unique(allocator); for (auto &domain : domains) { if (!present_timing->get_swapchain_time_domains().add_time_domain(std::move(domain))) { WSI_LOG_ERROR("Failed to add a time domain."); return nullptr; } } return present_timing; } /** * @brief Constructor for the wsi_ext_present_timing class. */ wsi_ext_present_timing(const util::allocator &allocator); /** * @brief Destructor for the wsi_ext_present_timing class. */ virtual ~wsi_ext_present_timing(); /** * @brief Set the queue size for the present timing queue. * * This API allows modifying the queue size of the present timing queue. * * @param queue_size The new queue size to set. * * @return VK_SUCCESS on if the queue size was updated correctly. * VK_NOT_READY when the number of present timing outstanding * items are larger than the queue size. VK_ERROR_OUT_OF_HOST_MEMORY * when there is no host memory available for the new size. */ VkResult present_timing_queue_set_size(size_t queue_size); /** * @brief Get the number of outstanding presnt timing results. * * This API allows getting the number of the current outstanding results. * * @return The size of the currently outstanding present timing items. */ size_t present_timing_get_num_outstanding_results(); /** * @brief Add a presentation entry to the present timing queue. * * This API pushes a presentation entry to the present timing queue. * * @param sc_presentation_entry Reference to the presentation entry to be added. * * @return VK_SUCCESS when the entry was inserted successfully and VK_ERROR_OUT_OF_HOST_MEMORY * when there is no host memory. */ VkResult add_presentation_entry(const wsi::swapchain_presentation_entry &sc_presentation_entry); /** * @brief Get the swapchain time domains */ swapchain_time_domains &get_swapchain_time_domains(); /** * @brief Backend specific implementation of the vkGetSwapchainTimingPropertiesEXT * entrypoint. * * @param timing_properties_counter Timing properties counter. * @param timing_properties Timing properties. * @return Vulkan result code. */ virtual VkResult get_swapchain_timing_properties(uint64_t &timing_properties_counter, VkSwapchainTimingPropertiesEXT &timing_properties) = 0; protected: /** * @brief User provided memory allocation callbacks. */ const util::allocator m_allocator; private: /** * @brief The presentation timing queue. */ timings_queue m_queue; /** * @brief Handle the backend specific time domains for each present stage. */ swapchain_time_domains m_time_domains; }; } /* namespace wsi */ #endif