Update present timing types

Updates the present timing implementation and types to be aligned with
the latest commit.

Fixes an issue, where the queue used for the presentation feedback
events was destroyed before getting the last events.

Signed-off-by: Iason Paraskevopoulos <iason.paraskevopoulos@arm.com>
Change-Id: I1dba2fd0e4ad9ec8c02d71c58c93edceaa75d07e
This commit is contained in:
Iason Paraskevopoulos 2025-09-04 16:48:10 +00:00 committed by Rosen Zhelev
parent 6baf6ff52a
commit b02e682d30
11 changed files with 84 additions and 85 deletions

View file

@ -60,16 +60,16 @@ wsi_layer_vkSetSwapchainPresentTimingQueueSizeEXT(VkDevice device, VkSwapchainKH
*/
VWL_VKAPI_CALL(VkResult)
wsi_layer_vkGetSwapchainTimingPropertiesEXT(VkDevice device, VkSwapchainKHR swapchain,
uint64_t *pSwapchainTimingPropertiesCounter,
VkSwapchainTimingPropertiesEXT *pSwapchainTimingProperties) VWL_API_POST
VkSwapchainTimingPropertiesEXT *pSwapchainTimingProperties,
uint64_t *pSwapchainTimingPropertiesCounter) VWL_API_POST
{
assert(swapchain != VK_NULL_HANDLE);
auto &device_data = layer::device_private_data::get(device);
if (!device_data.layer_owns_swapchain(swapchain))
{
return device_data.disp.GetSwapchainTimingPropertiesEXT(device, swapchain, pSwapchainTimingPropertiesCounter,
pSwapchainTimingProperties);
return device_data.disp.GetSwapchainTimingPropertiesEXT(device, swapchain, pSwapchainTimingProperties,
pSwapchainTimingPropertiesCounter);
}
auto *sc = reinterpret_cast<wsi::swapchain_base *>(swapchain);
@ -82,16 +82,16 @@ wsi_layer_vkGetSwapchainTimingPropertiesEXT(VkDevice device, VkSwapchainKHR swap
* @brief Implements vkGetSwapchainTimeDomainPropertiesEXT Vulkan entrypoint.
*/
VWL_VKAPI_CALL(VkResult)
wsi_layer_vkGetSwapchainTimeDomainPropertiesEXT(
VkDevice device, VkSwapchainKHR swapchain, uint64_t *pTimeDomainsCounter,
VkSwapchainTimeDomainPropertiesEXT *pSwapchainTimeDomainProperties) VWL_API_POST
wsi_layer_vkGetSwapchainTimeDomainPropertiesEXT(VkDevice device, VkSwapchainKHR swapchain,
VkSwapchainTimeDomainPropertiesEXT *pSwapchainTimeDomainProperties,
uint64_t *pTimeDomainsCounter) VWL_API_POST
{
auto &device_data = layer::device_private_data::get(device);
if (!device_data.layer_owns_swapchain(swapchain))
{
return device_data.disp.GetSwapchainTimeDomainPropertiesEXT(device, swapchain, pTimeDomainsCounter,
pSwapchainTimeDomainProperties);
return device_data.disp.GetSwapchainTimeDomainPropertiesEXT(device, swapchain, pSwapchainTimeDomainProperties,
pTimeDomainsCounter);
}
auto *sc = reinterpret_cast<wsi::swapchain_base *>(swapchain);

View file

@ -55,6 +55,7 @@
#define VK_SWAPCHAIN_CREATE_PRESENT_TIMING_BIT_EXT ((VkSwapchainCreateFlagsKHR)0x00010000)
typedef VkFlags VkPresentStageFlagsEXT;
typedef VkFlags VkPresentTimingInfoFlagsEXT;
typedef struct VkPhysicalDevicePresentTimingFeaturesEXT
{
@ -72,13 +73,12 @@ typedef struct VkPresentTimingSurfaceCapabilitiesEXT
VkBool32 presentAtAbsoluteTimeSupported;
VkBool32 presentAtRelativeTimeSupported;
VkPresentStageFlagsEXT presentStageQueries;
VkPresentStageFlagsEXT presentStageTargets;
} VkPresentTimingSurfaceCapabilitiesEXT;
typedef enum VkPresentStageFlagBitsEXT
{
VK_PRESENT_STAGE_QUEUE_OPERATIONS_END_BIT_EXT = 0x00000001,
VK_PRESENT_STAGE_IMAGE_LATCHED_BIT_EXT = 0x00000002,
VK_PRESENT_STAGE_REQUEST_DEQUEUED_BIT_EXT = 0x00000002,
VK_PRESENT_STAGE_IMAGE_FIRST_PIXEL_OUT_BIT_EXT = 0x00000004,
VK_PRESENT_STAGE_IMAGE_FIRST_PIXEL_VISIBLE_BIT_EXT = 0x00000008,
} VkPresentStageFlagBitsEXT;
@ -88,7 +88,7 @@ typedef struct VkSwapchainTimingPropertiesEXT
VkStructureType sType;
const void *pNext;
uint64_t refreshDuration;
uint64_t variableRefreshDelay;
uint64_t refreshInterval;
} VkSwapchainTimingPropertiesEXT;
typedef struct VkSwapchainTimeDomainPropertiesEXT
@ -118,11 +118,12 @@ typedef struct VkPresentStageTimeEXT
typedef struct VkPastPresentationTimingEXT
{
VkStructureType sType;
const void *pNext;
void *pNext;
uint64_t presentId;
uint64_t targetTime;
uint32_t presentStageCount;
VkPresentStageTimeEXT *pPresentStages;
VkTimeDomainEXT timeDomain;
VkTimeDomainKHR timeDomain;
uint64_t timeDomainId;
VkBool32 reportComplete;
} VkPastPresentationTimingEXT;
@ -145,6 +146,12 @@ typedef enum VkPastPresentationTimingFlagBitsEXT
VK_PAST_PRESENTATION_TIMING_ALLOW_OUT_OF_ORDER_RESULTS_BIT_EXT = 0x00000002,
} VkPastPresentationTimingFlagBitsEXT;
typedef enum VkPresentTimingInfoFlagBitsEXT
{
VK_PRESENT_TIMING_INFO_PRESENT_AT_RELATIVE_TIME_BIT_EXT = 0x00000001,
VK_PRESENT_TIMING_INFO_PRESENT_AT_NEAREST_REFRESH_CYCLE_BIT_EXT = 0x00000002,
} VkPresentTimingInfoFlagBitsEXT;
typedef struct VkPastPresentationTimingInfoEXT
{
VkStructureType sType;
@ -153,22 +160,14 @@ typedef struct VkPastPresentationTimingInfoEXT
VkSwapchainKHR swapchain;
} VkPastPresentationTimingInfoEXT;
typedef union VkPresentTimeEXT
{
uint64_t targetPresentTime;
uint64_t presentDuration;
} VkPresentTimeEXT;
typedef struct VkPresentTimingInfoEXT
{
VkStructureType sType;
const void *pNext;
VkPresentTimeEXT time;
VkPresentTimingInfoFlagsEXT flags;
uint64_t targetTime;
uint64_t timeDomainId;
VkPresentStageFlagsEXT presentStageQueries;
VkPresentStageFlagsEXT targetPresentStage;
VkBool32 presentAtRelativeTime;
VkBool32 presentAtNearestRefreshCycle;
} VkPresentTimingInfoEXT;
typedef struct VkPresentTimingsInfoEXT
@ -180,12 +179,12 @@ typedef struct VkPresentTimingsInfoEXT
} VkPresentTimingsInfoEXT;
typedef VkResult(VKAPI_PTR *PFN_vkGetSwapchainTimeDomainPropertiesEXT)(
VkDevice device, VkSwapchainKHR swapchain, uint64_t *pTimeDomainsCounter,
VkSwapchainTimeDomainPropertiesEXT *pSwapchainTimeDomainProperties);
VkDevice device, VkSwapchainKHR swapchain, VkSwapchainTimeDomainPropertiesEXT *pSwapchainTimeDomainProperties,
uint64_t *pTimeDomainsCounter);
typedef VkResult(VKAPI_PTR *PFN_vkGetSwapchainTimingPropertiesEXT)(
VkDevice device, VkSwapchainKHR swapchain, uint64_t *pSwapchainTimingPropertiesCounter,
VkSwapchainTimingPropertiesEXT *pSwapchainTimingProperties);
VkDevice device, VkSwapchainKHR swapchain, VkSwapchainTimingPropertiesEXT *pSwapchainTimingProperties,
uint64_t *pSwapchainTimingPropertiesCounter);
typedef VkResult(VKAPI_PTR *PFN_vkSetSwapchainPresentTimingQueueSizeEXT)(VkDevice device, VkSwapchainKHR swapchain,
uint32_t size);
@ -200,12 +199,12 @@ wsi_layer_vkSetSwapchainPresentTimingQueueSizeEXT(VkDevice device, VkSwapchainKH
VWL_VKAPI_CALL(VkResult)
wsi_layer_vkGetSwapchainTimingPropertiesEXT(VkDevice device, VkSwapchainKHR swapchain,
uint64_t *pSwapchainTimingPropertiesCounter,
VkSwapchainTimingPropertiesEXT *pSwapchainTimingProperties) VWL_API_POST;
VkSwapchainTimingPropertiesEXT *pSwapchainTimingProperties,
uint64_t *pSwapchainTimingPropertiesCounter) VWL_API_POST;
VWL_VKAPI_CALL(VkResult)
wsi_layer_vkGetSwapchainTimeDomainPropertiesEXT(
VkDevice device, VkSwapchainKHR swapchain, uint64_t *pTimeDomainsCounter,
VkSwapchainTimeDomainPropertiesEXT *pSwapchainTimeDomainProperties) VWL_API_POST;
wsi_layer_vkGetSwapchainTimeDomainPropertiesEXT(VkDevice device, VkSwapchainKHR swapchain,
VkSwapchainTimeDomainPropertiesEXT *pSwapchainTimeDomainProperties,
uint64_t *pTimeDomainsCounter) VWL_API_POST;
VWL_VKAPI_CALL(VkResult)
wsi_layer_vkGetPastPresentationTimingEXT(

View file

@ -576,7 +576,6 @@ VkResult surface_properties::get_present_timing_surface_caps(
present_timing_surface_caps->presentAtAbsoluteTimeSupported = VK_FALSE;
present_timing_surface_caps->presentAtRelativeTimeSupported = VK_FALSE;
present_timing_surface_caps->presentStageQueries = 0;
present_timing_surface_caps->presentStageTargets = 0;
return VK_SUCCESS;
}

View file

@ -39,13 +39,13 @@
namespace wsi
{
/* VK_PRESENT_STAGE_QUEUE_OPERATIONS_END_BIT_EXT,
* VK_PRESENT_STAGE_IMAGE_LATCHED_BIT_EXT,
* 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
*/
static constexpr size_t MAX_PRESENT_STAGES = 4;
const std::array<VkPresentStageFlagBitsEXT, MAX_PRESENT_STAGES> g_present_stages = {
VK_PRESENT_STAGE_QUEUE_OPERATIONS_END_BIT_EXT, VK_PRESENT_STAGE_IMAGE_LATCHED_BIT_EXT,
VK_PRESENT_STAGE_QUEUE_OPERATIONS_END_BIT_EXT, 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
};
@ -276,6 +276,7 @@ VkResult wsi_ext_present_timing::queue_submit_queue_end_timing(const layer::devi
}
VkResult wsi_ext_present_timing::add_presentation_query_entry(VkQueue queue, uint64_t present_id, uint32_t image_index,
uint64_t target_time,
VkPresentStageFlagsEXT present_stage_queries)
{
const std::lock_guard<std::mutex> lock(m_queue_mutex);
@ -287,7 +288,7 @@ VkResult wsi_ext_present_timing::add_presentation_query_entry(VkQueue queue, uin
return VK_ERROR_PRESENT_TIMING_QUEUE_FULL_EXT;
}
wsi::swapchain_presentation_entry presentation_entry(present_stage_queries, present_id, image_index);
wsi::swapchain_presentation_entry presentation_entry(target_time, present_stage_queries, present_id, image_index);
if (!m_queue.try_push_back(std::move(presentation_entry)))
{
return VK_ERROR_OUT_OF_HOST_MEMORY;
@ -303,7 +304,7 @@ VkResult wsi_ext_present_timing::add_presentation_query_entry(VkQueue queue, uin
void wsi_ext_present_timing::add_presentation_target_entry(uint32_t image_index,
const VkPresentTimingInfoEXT &timing_info)
{
assert(timing_info.targetPresentStage);
assert(timing_info.targetTime != 0);
m_scheduled_present_targets[image_index] = scheduled_present_target(timing_info);
}
@ -322,9 +323,10 @@ VkResult wsi_ext_present_timing::add_presentation_entry(VkQueue queue, uint64_t
{
if (timing_info.presentStageQueries)
{
TRY_LOG_CALL(add_presentation_query_entry(queue, present_id, image_index, timing_info.presentStageQueries));
TRY_LOG_CALL(add_presentation_query_entry(queue, present_id, image_index, timing_info.targetTime,
timing_info.presentStageQueries));
}
if (timing_info.targetPresentStage)
if (timing_info.targetTime != 0)
{
add_presentation_target_entry(image_index, timing_info);
}
@ -462,9 +464,11 @@ bool wsi_ext_present_timing::is_stage_pending_for_image_index(uint32_t image_ind
return (get_pending_stage_timing(image_index, present_stage) != nullptr);
}
swapchain_presentation_entry::swapchain_presentation_entry(VkPresentStageFlagsEXT present_stage_queries,
swapchain_presentation_entry::swapchain_presentation_entry(uint64_t target_time,
VkPresentStageFlagsEXT present_stage_queries,
uint64_t present_id, uint32_t image_index)
: m_target_stages(0)
: m_target_time(target_time)
, m_target_stages(0)
, m_present_id(present_id)
, m_image_index(image_index)
, m_num_present_stages(0)
@ -474,7 +478,7 @@ swapchain_presentation_entry::swapchain_presentation_entry(VkPresentStageFlagsEX
m_queue_end_timing = swapchain_presentation_timing();
m_num_present_stages++;
}
if (present_stage_queries & VK_PRESENT_STAGE_IMAGE_LATCHED_BIT_EXT)
if (present_stage_queries & VK_PRESENT_STAGE_REQUEST_DEQUEUED_BIT_EXT)
{
m_latch_timing = swapchain_presentation_timing();
m_num_present_stages++;
@ -510,7 +514,7 @@ bool swapchain_presentation_entry::is_pending(VkPresentStageFlagBitsEXT stage)
bool swapchain_presentation_entry::has_outstanding_stages()
{
return (is_pending(VK_PRESENT_STAGE_QUEUE_OPERATIONS_END_BIT_EXT) ||
is_pending(VK_PRESENT_STAGE_IMAGE_LATCHED_BIT_EXT) ||
is_pending(VK_PRESENT_STAGE_REQUEST_DEQUEUED_BIT_EXT) ||
is_pending(VK_PRESENT_STAGE_IMAGE_FIRST_PIXEL_OUT_BIT_EXT) ||
is_pending(VK_PRESENT_STAGE_IMAGE_FIRST_PIXEL_VISIBLE_BIT_EXT));
}
@ -544,7 +548,7 @@ std::optional<std::reference_wrapper<swapchain_presentation_timing>> swapchain_p
return *m_queue_end_timing;
}
break;
case VK_PRESENT_STAGE_IMAGE_LATCHED_BIT_EXT:
case VK_PRESENT_STAGE_REQUEST_DEQUEUED_BIT_EXT:
if (m_latch_timing.has_value())
{
return *m_latch_timing;
@ -602,6 +606,7 @@ void swapchain_presentation_entry::populate(VkPastPresentationTimingEXT &timing)
{
timing.presentId = m_present_id;
timing.reportComplete = !has_outstanding_stages();
timing.targetTime = m_target_time;
}
}

View file

@ -99,6 +99,11 @@ struct swapchain_presentation_timing
*/
struct swapchain_presentation_entry
{
/**
* Target time used in the present request.
*/
uint64_t m_target_time{ 0 };
/**
* The target stages for the presentation entry.
*/
@ -127,7 +132,7 @@ struct swapchain_presentation_entry
std::optional<swapchain_presentation_timing> m_first_pixel_out_timing;
std::optional<swapchain_presentation_timing> m_first_pixel_visible_timing;
swapchain_presentation_entry(VkPresentStageFlagsEXT present_stage_queries, uint64_t present_id,
swapchain_presentation_entry(uint64_t target_time, VkPresentStageFlagsEXT present_stage_queries, uint64_t present_id,
uint32_t image_index);
swapchain_presentation_entry(swapchain_presentation_entry &&) noexcept = default;
swapchain_presentation_entry &operator=(swapchain_presentation_entry &&) noexcept = default;
@ -292,19 +297,15 @@ private:
struct scheduled_present_target
{
scheduled_present_target(const VkPresentTimingInfoEXT &timing_info)
: m_target_stage(timing_info.targetPresentStage)
, m_time_domain_id(timing_info.timeDomainId)
, m_present_at_nearest_refresh_cycle(timing_info.presentAtNearestRefreshCycle)
, m_present_at_relative_time(timing_info.presentAtRelativeTime)
, m_target_present_time(timing_info.time)
: m_time_domain_id(timing_info.timeDomainId)
, m_flags(timing_info.flags)
, m_target_present_time(timing_info.targetTime)
{
}
VkPresentStageFlagsEXT m_target_stage;
uint64_t m_time_domain_id;
bool m_present_at_nearest_refresh_cycle;
bool m_present_at_relative_time;
VkPresentTimeEXT m_target_present_time;
VkPresentTimingInfoFlagsEXT m_flags;
uint64_t m_target_present_time;
};
/**
@ -378,12 +379,13 @@ public:
* @param queue The Vulkan queue used to submit synchronization commands.
* @param present_id The present id of the current presentation.
* @param image_index The index of the image in the swapchain.
* @param target_time The target time for the presentation.
* @param present_stage_queries The present stages application had requested timings for.
*
* @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_query_entry(VkQueue queue, uint64_t present_id, uint32_t image_index,
VkResult add_presentation_query_entry(VkQueue queue, uint64_t present_id, uint32_t image_index, uint64_t target_time,
VkPresentStageFlagsEXT present_stage_queries);
/**

View file

@ -82,8 +82,8 @@ util::unique_ptr<wsi_ext_present_timing_headless> wsi_ext_present_timing_headles
if (monotonic_domain)
{
if (!domains.try_push_back(
allocator.make_unique<wsi::vulkan_time_domain>(VK_PRESENT_STAGE_IMAGE_LATCHED_BIT_EXT, *monotonic_domain)))
if (!domains.try_push_back(allocator.make_unique<wsi::vulkan_time_domain>(
VK_PRESENT_STAGE_REQUEST_DEQUEUED_BIT_EXT, *monotonic_domain)))
{
return nullptr;
}
@ -116,7 +116,7 @@ VkResult wsi_ext_present_timing_headless::get_swapchain_timing_properties(
timing_properties_counter = 1;
timing_properties.refreshDuration = fixed_refresh_duration_ns;
timing_properties.variableRefreshDelay = UINT64_MAX;
timing_properties.refreshInterval = fixed_refresh_duration_ns;
return VK_SUCCESS;
}

View file

@ -261,14 +261,13 @@ VkResult surface_properties::get_present_timing_surface_caps(
[](auto &domain) { return std::get<1>(domain); });
if (it_monotonic_supported != monotonic_domains.end())
{
monotonic_present_stages_supported |= VK_PRESENT_STAGE_IMAGE_LATCHED_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_VISIBLE_BIT_EXT;
}
present_timing_surface_caps->presentStageQueries =
VK_PRESENT_STAGE_QUEUE_OPERATIONS_END_BIT_EXT | monotonic_present_stages_supported;
present_timing_surface_caps->presentStageTargets = monotonic_present_stages_supported;
return VK_SUCCESS;
}

View file

@ -224,19 +224,14 @@ void swapchain::present_image(const pending_present_request &pending_present)
{
auto presentation_target = ext_present_timing->get_presentation_target_entry(pending_present.image_index);
if (presentation_target)
{
const VkPresentStageFlagsEXT supported_target_stages = VK_PRESENT_STAGE_IMAGE_LATCHED_BIT_EXT |
VK_PRESENT_STAGE_IMAGE_FIRST_PIXEL_OUT_BIT_EXT |
VK_PRESENT_STAGE_IMAGE_FIRST_PIXEL_VISIBLE_BIT_EXT;
if ((presentation_target->m_target_stage & supported_target_stages) != 0)
{
/* No support for relative presentation mode currently */
assert(!presentation_target->m_present_at_relative_time);
if (!presentation_target->m_present_at_relative_time)
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))
{
/* 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.targetPresentTime;
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)
{
@ -249,7 +244,6 @@ void swapchain::present_image(const pending_present_request &pending_present)
}
}
}
}
ext_present_timing->remove_presentation_target_entry(pending_present.image_index);
}
@ -272,7 +266,7 @@ void swapchain::present_image(const pending_present_request &pending_present)
}
VkPresentStageFlagBitsEXT stages[] = {
VK_PRESENT_STAGE_IMAGE_LATCHED_BIT_EXT,
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,
};

View file

@ -92,7 +92,7 @@ VkResult wsi_ext_present_timing_wayland::get_swapchain_timing_properties(
{
timing_properties_counter = 0;
timing_properties.refreshDuration = 0;
timing_properties.variableRefreshDelay = 0;
timing_properties.refreshInterval = 0;
return VK_SUCCESS;
}

View file

@ -467,10 +467,10 @@ VkResult surface_properties::get_present_timing_surface_caps(
/* The extension supports scheduling targets only on FIFO & FIFO_RELAXED modes. We currently only have
support for scheduling presents when using the presentation thread. While FIFO runs on Wayland in
threaded mode, FIFO_RELAXED does not. If you are adding any supported stage to presentStageTargets,
make sure to check that swapchain cannot be created with present timing support on present modes that
threaded mode, FIFO_RELAXED does not. If you are setting presentAtAbsoluteTimeSupported or
presentAtRelativeTimeSupported to VK_TRUE, make sure to check that swapchain cannot be created
with present timing support on present modes that
do not use presentation thread unless support has been added in other ways. */
present_timing_surface_caps->presentStageTargets = 0;
if (specific_surface->get_presentation_time_interface() != nullptr)
{

View file

@ -77,6 +77,7 @@ swapchain::~swapchain()
if (m_buffer_queue != nullptr)
{
wl_display_roundtrip_queue(m_display, m_buffer_queue);
wl_event_queue_destroy(m_buffer_queue);
}
}