diff --git a/wsi/wayland/present_timing_handler.cpp b/wsi/wayland/present_timing_handler.cpp index 12bdf78..fb7b580 100644 --- a/wsi/wayland/present_timing_handler.cpp +++ b/wsi/wayland/present_timing_handler.cpp @@ -37,11 +37,13 @@ wsi_ext_present_timing_wayland::wsi_ext_present_timing_wayland(const util::alloc } util::unique_ptr wsi_ext_present_timing_wayland::create( - const util::allocator &allocator) + VkTimeDomainKHR image_first_pixel_visible_time_domain, const util::allocator &allocator) { - std::array, 1> time_domains_array = { + std::array, 2> time_domains_array = { allocator.make_unique(VK_PRESENT_STAGE_QUEUE_OPERATIONS_END_BIT_EXT, - VK_TIME_DOMAIN_DEVICE_KHR) + VK_TIME_DOMAIN_DEVICE_KHR), + allocator.make_unique(VK_PRESENT_STAGE_IMAGE_FIRST_PIXEL_VISIBLE_BIT_EXT, + image_first_pixel_visible_time_domain) }; return wsi_ext_present_timing::create(allocator, time_domains_array); @@ -55,4 +57,4 @@ VkResult wsi_ext_present_timing_wayland::get_swapchain_timing_properties( timing_properties.variableRefreshDelay = 0; return VK_SUCCESS; -} \ No newline at end of file +} diff --git a/wsi/wayland/present_timing_handler.hpp b/wsi/wayland/present_timing_handler.hpp index 7644c83..c7e19d9 100644 --- a/wsi/wayland/present_timing_handler.hpp +++ b/wsi/wayland/present_timing_handler.hpp @@ -41,7 +41,8 @@ class wsi_ext_present_timing_wayland : public wsi::wsi_ext_present_timing { public: - static util::unique_ptr create(const util::allocator &allocator); + static util::unique_ptr create(VkTimeDomainKHR image_first_pixel_visible_time_domain, + const util::allocator &allocator); VkResult get_swapchain_timing_properties(uint64_t &timing_properties_counter, VkSwapchainTimingPropertiesEXT &timing_properties) override; diff --git a/wsi/wayland/surface.cpp b/wsi/wayland/surface.cpp index 38ff3b3..f65680f 100644 --- a/wsi/wayland/surface.cpp +++ b/wsi/wayland/surface.cpp @@ -72,9 +72,21 @@ zwp_linux_dmabuf_v1_modifier_impl(void *data, struct zwp_linux_dmabuf_v1 *dma_bu drm_supported_formats->is_out_of_memory = !drm_supported_formats->formats->try_push_back(format); } } + +/* Handler for clock_id event of the wp_presentation interface. */ +VWL_CAPI_CALL(void) +wp_presentation_clock_id_impl(void *data, struct wp_presentation *wp_presentation, + uint32_t compositor_clockid) VWL_API_POST +{ + UNUSED(wp_presentation); + + clockid_t *clockid = static_cast(data); + *clockid = compositor_clockid; +} + } // namespace -/* +/** * @brief Get supported formats and modifiers using the zwp_linux_dmabuf_v1 interface. * * @param[in] display The wl_display that is being used. @@ -122,6 +134,35 @@ static VkResult get_supported_formats_and_modifiers(wl_display *display, wl_even return VK_SUCCESS; } +/** + * @brief Set the clock_id using the wp_presentation interface + * + * @retval VK_SUCCESS Indicates success. + * @retval VK_ERROR_UNKNOWN Indicates one of the Wayland functions failed. + */ +static VkResult get_clock_id(wl_display *display, wl_event_queue *queue, wp_presentation *presentation_interface, + clockid_t *clockid) +{ + const wp_presentation_listener presentation_listener = { + .clock_id = wp_presentation_clock_id_impl, + }; + + int res = wp_presentation_add_listener(presentation_interface, &presentation_listener, clockid); + if (res < 0) + { + WSI_LOG_ERROR("Failed to add wp_presentation listener."); + return VK_ERROR_UNKNOWN; + } + + res = wl_display_roundtrip_queue(display, queue); + if (res < 0) + { + WSI_LOG_ERROR("Roundtrip failed."); + return VK_ERROR_UNKNOWN; + } + return VK_SUCCESS; +} + struct surface::init_parameters { const util::allocator &allocator; @@ -262,6 +303,12 @@ bool surface::init() return false; } + vk_res = get_clock_id(wayland_display, surface_queue.get(), presentation_time_interface.get(), &m_clockid); + if (vk_res != VK_SUCCESS) + { + return false; + } + return true; } diff --git a/wsi/wayland/surface.hpp b/wsi/wayland/surface.hpp index bf21a35..24cb938 100644 --- a/wsi/wayland/surface.hpp +++ b/wsi/wayland/surface.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2025 Arm Limited. + * Copyright (c) 2021, 2024-2025 Arm Limited. * * SPDX-License-Identifier: MIT * @@ -31,6 +31,7 @@ #ifndef __STDC_VERSION__ #define __STDC_VERSION__ 0 #endif +#include #include #include "wsi/surface.hpp" @@ -149,6 +150,14 @@ public: */ bool wait_next_frame_event(); + /** + * @brief Return the clockid of the surface + */ + clockid_t clockid() + { + return m_clockid; + } + private: /** * @brief Initialize the WSI surface by creating Wayland queues and linking to Wayland protocols. @@ -189,7 +198,7 @@ private: wayland_owner presentation_time_interface; /** - * Container for a callback object for the latest frame done event. + * @brief Container for a callback object for the latest frame done event. * * The callback object should be destroyed before the queue so any new events * on the queue will be discarded. If a proxy object is destroyed after a queue, @@ -205,6 +214,11 @@ private: * callback to indicate the server is ready for the next buffer. */ bool present_pending; + + /** + * @brief Stores the clock ID reported by the wp_presentation interface + */ + clockid_t m_clockid; }; } // namespace wayland diff --git a/wsi/wayland/surface_properties.cpp b/wsi/wayland/surface_properties.cpp index 31ddc68..127a72d 100644 --- a/wsi/wayland/surface_properties.cpp +++ b/wsi/wayland/surface_properties.cpp @@ -424,7 +424,8 @@ void surface_properties::get_present_timing_surface_caps( present_timing_surface_caps->presentTimingSupported = VK_TRUE; present_timing_surface_caps->presentAtAbsoluteTimeSupported = VK_FALSE; present_timing_surface_caps->presentAtRelativeTimeSupported = VK_FALSE; - present_timing_surface_caps->presentStageQueries = VK_PRESENT_STAGE_QUEUE_OPERATIONS_END_BIT_EXT; + present_timing_surface_caps->presentStageQueries = + VK_PRESENT_STAGE_QUEUE_OPERATIONS_END_BIT_EXT | VK_PRESENT_STAGE_IMAGE_FIRST_PIXEL_VISIBLE_BIT_EXT; present_timing_surface_caps->presentStageTargets = 0; } #endif diff --git a/wsi/wayland/swapchain.cpp b/wsi/wayland/swapchain.cpp index 0638d2d..7ae5199 100644 --- a/wsi/wayland/swapchain.cpp +++ b/wsi/wayland/swapchain.cpp @@ -127,7 +127,18 @@ VkResult swapchain::add_required_extensions(VkDevice device, const VkSwapchainCr bool swapchain_support_enabled = swapchain_create_info->flags & VK_SWAPCHAIN_CREATE_PRESENT_TIMING_BIT_EXT; if (swapchain_support_enabled) { - if (!add_swapchain_extension(wsi_ext_present_timing_wayland::create(m_allocator))) + /* + * Default to a raw hardware-based time that is not subject to NTP adjustments or + * the incremental adjustments performed by adjtime(3) + */ + VkTimeDomainKHR image_first_pixel_visible_time_domain = VK_TIME_DOMAIN_CLOCK_MONOTONIC_RAW_KHR; + + if (m_wsi_surface->clockid() == CLOCK_MONOTONIC) + { + image_first_pixel_visible_time_domain = VK_TIME_DOMAIN_CLOCK_MONOTONIC_KHR; + } + if (!add_swapchain_extension( + wsi_ext_present_timing_wayland::create(image_first_pixel_visible_time_domain, m_allocator))) { return VK_ERROR_OUT_OF_HOST_MEMORY; }