diff --git a/wsi/headless/present_timing_handler.cpp b/wsi/headless/present_timing_handler.cpp index 9d72089..e6df6ee 100644 --- a/wsi/headless/present_timing_handler.cpp +++ b/wsi/headless/present_timing_handler.cpp @@ -151,4 +151,17 @@ std::optional wsi_ext_present_timing_headless::get_current_clock_time_ return now.tv_sec * static_cast(1e9) + now.tv_nsec; } +std::optional wsi_ext_present_timing_headless::get_first_pixel_visible_timestamp_for_last_image() const +{ + if (!m_first_pixel_visible_timestamp_for_last_image.has_value()) + { + return std::nullopt; + } + return m_first_pixel_visible_timestamp_for_last_image.value(); +} + +void wsi_ext_present_timing_headless::set_first_pixel_visible_timestamp_for_last_image(uint64_t timestamp) +{ + m_first_pixel_visible_timestamp_for_last_image = timestamp; +} #endif diff --git a/wsi/headless/present_timing_handler.hpp b/wsi/headless/present_timing_handler.hpp index e90c713..f911d83 100644 --- a/wsi/headless/present_timing_handler.hpp +++ b/wsi/headless/present_timing_handler.hpp @@ -67,6 +67,19 @@ public: */ std::optional get_current_clock_time_ns() const; + /** + * @brief Get the first pixel visible timestamp for the last presented image. + * + * @return first pixel visible timestamp for the last presented image or std::nullopt in case of error. + */ + std::optional get_first_pixel_visible_timestamp_for_last_image() const; + + /** + * @brief Caches the first pixel visible timestamp for the last presented image. + * + */ + void set_first_pixel_visible_timestamp_for_last_image(uint64_t timestamp); + private: wsi_ext_present_timing_headless(const util::allocator &allocator, VkDevice device, uint32_t num_images, std::optional monotonic_domain); @@ -76,6 +89,11 @@ private: /* Monotonic time domain supported by the driver */ std::optional m_monotonic_domain; + + /** + * Timestamp for the last VK_PRESENT_STAGE_IMAGE_FIRST_PIXEL_VISIBLE_BIT_EXT stage. + */ + std::optional m_first_pixel_visible_timestamp_for_last_image; }; #endif diff --git a/wsi/headless/surface_properties.cpp b/wsi/headless/surface_properties.cpp index 0674416..2487548 100644 --- a/wsi/headless/surface_properties.cpp +++ b/wsi/headless/surface_properties.cpp @@ -247,7 +247,7 @@ VkResult surface_properties::get_present_timing_surface_caps( VkPhysicalDevice physical_device, VkPresentTimingSurfaceCapabilitiesEXT *present_timing_surface_caps) { present_timing_surface_caps->presentTimingSupported = VK_TRUE; - present_timing_surface_caps->presentAtAbsoluteTimeSupported = VK_TRUE; + present_timing_surface_caps->presentAtAbsoluteTimeSupported = VK_FALSE; present_timing_surface_caps->presentAtRelativeTimeSupported = VK_FALSE; VkPresentStageFlagsEXT monotonic_present_stages_supported = 0; @@ -264,6 +264,8 @@ VkResult surface_properties::get_present_timing_surface_caps( monotonic_present_stages_supported |= VK_PRESENT_STAGE_REQUEST_DEQUEUED_BIT_EXT | VK_PRESENT_STAGE_IMAGE_FIRST_PIXEL_OUT_BIT_EXT | VK_PRESENT_STAGE_IMAGE_FIRST_PIXEL_VISIBLE_BIT_EXT; + present_timing_surface_caps->presentAtAbsoluteTimeSupported = VK_TRUE; + present_timing_surface_caps->presentAtRelativeTimeSupported = VK_TRUE; } present_timing_surface_caps->presentStageQueries = diff --git a/wsi/headless/swapchain.cpp b/wsi/headless/swapchain.cpp index df4d88e..89b6b88 100644 --- a/wsi/headless/swapchain.cpp +++ b/wsi/headless/swapchain.cpp @@ -227,25 +227,35 @@ void swapchain::present_image(const pending_present_request &pending_present) if (ext_present_timing) { auto presentation_target = ext_present_timing->get_presentation_target_entry(pending_present.image_index); + uint64_t absolute_future_present_time_ns = 0; if (presentation_target) { - /* No support for relative presentation mode currently */ - assert(!(presentation_target->m_flags & VK_PRESENT_TIMING_INFO_PRESENT_AT_RELATIVE_TIME_BIT_EXT)); - if (!(presentation_target->m_flags & VK_PRESENT_TIMING_INFO_PRESENT_AT_RELATIVE_TIME_BIT_EXT)) + if (presentation_target->m_flags & VK_PRESENT_TIMING_INFO_PRESENT_AT_RELATIVE_TIME_BIT_EXT) + { + std::optional first_pixel_visible_timestamp_for_last_image = + ext_present_timing->get_first_pixel_visible_timestamp_for_last_image(); + + if (first_pixel_visible_timestamp_for_last_image.has_value()) + { + absolute_future_present_time_ns = + first_pixel_visible_timestamp_for_last_image.value() + presentation_target->m_target_present_time; + } + } + else { /* No need to check whether we need to present at nearest refresh cycle since this backend is not limited by the refresh cycles. */ - uint64_t absolute_future_present_time_ns = presentation_target->m_target_present_time; - auto current_time_ns = ext_present_timing->get_current_clock_time_ns(); - if (*current_time_ns < absolute_future_present_time_ns) - { - /* Sleep until we can schedule the image for completion. - * This is OK as the sleep should only be dispatched on the page_flip thread and not on main. */ - assert(m_page_flip_thread_run); + absolute_future_present_time_ns = presentation_target->m_target_present_time; + } + auto current_time_ns = ext_present_timing->get_current_clock_time_ns(); + if (*current_time_ns < absolute_future_present_time_ns) + { + /* Sleep until we can schedule the image for completion. + * This is OK as the sleep should only be dispatched on the page_flip thread and not on main. */ + assert(m_page_flip_thread_run); - int64_t time_diff = absolute_future_present_time_ns - *current_time_ns; - std::this_thread::sleep_for(std::chrono::nanoseconds(time_diff)); - } + int64_t time_diff = absolute_future_present_time_ns - *current_time_ns; + std::this_thread::sleep_for(std::chrono::nanoseconds(time_diff)); } } @@ -268,6 +278,7 @@ void swapchain::present_image(const pending_present_request &pending_present) /* Set all times to 0 as we were not able to query them. */ current_time = 0; } + ext_present_timing->set_first_pixel_visible_timestamp_for_last_image(*current_time); VkPresentStageFlagBitsEXT stages[] = { VK_PRESENT_STAGE_REQUEST_DEQUEUED_BIT_EXT,