Merge 'Implement schedule present at relative time on headless' into 'main'

See merge request mesa/vulkan-wsi-layer!201
This commit is contained in:
Rosen Zhelev 2025-09-15 12:40:06 +01:00
commit 623f803387
4 changed files with 58 additions and 14 deletions

View file

@ -151,4 +151,17 @@ std::optional<uint64_t> wsi_ext_present_timing_headless::get_current_clock_time_
return now.tv_sec * static_cast<uint64_t>(1e9) + now.tv_nsec; return now.tv_sec * static_cast<uint64_t>(1e9) + now.tv_nsec;
} }
std::optional<uint64_t> 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 #endif

View file

@ -67,6 +67,19 @@ public:
*/ */
std::optional<uint64_t> get_current_clock_time_ns() const; std::optional<uint64_t> 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<uint64_t> 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: private:
wsi_ext_present_timing_headless(const util::allocator &allocator, VkDevice device, uint32_t num_images, wsi_ext_present_timing_headless(const util::allocator &allocator, VkDevice device, uint32_t num_images,
std::optional<VkTimeDomainEXT> monotonic_domain); std::optional<VkTimeDomainEXT> monotonic_domain);
@ -76,6 +89,11 @@ private:
/* Monotonic time domain supported by the driver */ /* Monotonic time domain supported by the driver */
std::optional<VkTimeDomainEXT> m_monotonic_domain; std::optional<VkTimeDomainEXT> m_monotonic_domain;
/**
* Timestamp for the last VK_PRESENT_STAGE_IMAGE_FIRST_PIXEL_VISIBLE_BIT_EXT stage.
*/
std::optional<uint64_t> m_first_pixel_visible_timestamp_for_last_image;
}; };
#endif #endif

View file

@ -247,7 +247,7 @@ VkResult surface_properties::get_present_timing_surface_caps(
VkPhysicalDevice physical_device, VkPresentTimingSurfaceCapabilitiesEXT *present_timing_surface_caps) VkPhysicalDevice physical_device, VkPresentTimingSurfaceCapabilitiesEXT *present_timing_surface_caps)
{ {
present_timing_surface_caps->presentTimingSupported = VK_TRUE; 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; present_timing_surface_caps->presentAtRelativeTimeSupported = VK_FALSE;
VkPresentStageFlagsEXT monotonic_present_stages_supported = 0; 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 | 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_OUT_BIT_EXT |
VK_PRESENT_STAGE_IMAGE_FIRST_PIXEL_VISIBLE_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 = present_timing_surface_caps->presentStageQueries =

View file

@ -227,25 +227,35 @@ void swapchain::present_image(const pending_present_request &pending_present)
if (ext_present_timing) if (ext_present_timing)
{ {
auto presentation_target = ext_present_timing->get_presentation_target_entry(pending_present.image_index); 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) if (presentation_target)
{ {
/* No support for relative presentation mode currently */ if (presentation_target->m_flags & VK_PRESENT_TIMING_INFO_PRESENT_AT_RELATIVE_TIME_BIT_EXT)
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)) std::optional<uint64_t> 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 /* No need to check whether we need to present at nearest refresh cycle since this backend is not
limited by the refresh cycles. */ limited by the refresh cycles. */
uint64_t absolute_future_present_time_ns = presentation_target->m_target_present_time; 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) 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. */ /* Sleep until we can schedule the image for completion.
assert(m_page_flip_thread_run); * 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; int64_t time_diff = absolute_future_present_time_ns - *current_time_ns;
std::this_thread::sleep_for(std::chrono::nanoseconds(time_diff)); 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. */ /* Set all times to 0 as we were not able to query them. */
current_time = 0; current_time = 0;
} }
ext_present_timing->set_first_pixel_visible_timestamp_for_last_image(*current_time);
VkPresentStageFlagBitsEXT stages[] = { VkPresentStageFlagBitsEXT stages[] = {
VK_PRESENT_STAGE_REQUEST_DEQUEUED_BIT_EXT, VK_PRESENT_STAGE_REQUEST_DEQUEUED_BIT_EXT,