mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2024-11-23 02:04:41 +08:00
vulkan/wsi/wayland: Move timing calculations to the swapchain
When we create a new swapchain to replace the one currently presenting on
a surface, we need to reset all these timing variables. Otherwise we can
lose track of corrections that were made for the old swapchain when we
delete undelivered presentation feedback results.
Also, we use these variables when queuing a presentation, but we also use
them in the dispatch code that can be called by WaitForPresent from another
thread. We need to protect these variables against concurrent usage.
This is all much easier to do when they're stored as part of the swapchain
instead of the surface, so just move them there and adjust the locking.
Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
Fixes: c26ab1aee1
("vulkan/wsi/wayland: Pace frames with commit-timing-v1")
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/32121>
This commit is contained in:
parent
b9c8afae33
commit
2e49448a43
@ -176,12 +176,6 @@ struct wsi_wl_surface {
|
||||
uint64_t presentation_track_id;
|
||||
} analytics;
|
||||
|
||||
uint64_t last_target_time;
|
||||
uint64_t displayed_time;
|
||||
bool valid_refresh_nsec;
|
||||
unsigned int refresh_nsec;
|
||||
uint64_t display_time_error;
|
||||
uint64_t display_time_correction;
|
||||
struct zwp_linux_dmabuf_feedback_v1 *wl_dmabuf_feedback;
|
||||
struct dmabuf_feedback dmabuf_feedback, pending_dmabuf_feedback;
|
||||
|
||||
@ -223,6 +217,13 @@ struct wsi_wl_swapchain {
|
||||
/* Fallback when wp_presentation is not supported */
|
||||
struct wl_surface *surface;
|
||||
bool dispatch_in_progress;
|
||||
|
||||
uint64_t display_time_error;
|
||||
uint64_t display_time_correction;
|
||||
uint64_t last_target_time;
|
||||
uint64_t displayed_time;
|
||||
bool valid_refresh_nsec;
|
||||
unsigned int refresh_nsec;
|
||||
} present_ids;
|
||||
|
||||
struct wsi_wl_image images[0];
|
||||
@ -1798,8 +1799,6 @@ static VkResult wsi_wl_surface_init(struct wsi_wl_surface *wsi_wl_surface,
|
||||
|
||||
wsi_wl_surface_analytics_init(wsi_wl_surface, pAllocator);
|
||||
|
||||
wsi_wl_surface->valid_refresh_nsec = false;
|
||||
wsi_wl_surface->refresh_nsec = 0;
|
||||
return VK_SUCCESS;
|
||||
|
||||
fail:
|
||||
@ -2161,7 +2160,7 @@ wsi_wl_presentation_update_present_id(struct wsi_wl_present_id *id)
|
||||
if (id->present_id > id->chain->present_ids.max_completed)
|
||||
id->chain->present_ids.max_completed = id->present_id;
|
||||
|
||||
id->chain->wsi_wl_surface->display_time_correction -= id->correction;
|
||||
id->chain->present_ids.display_time_correction -= id->correction;
|
||||
wl_list_remove(&id->link);
|
||||
mtx_unlock(&id->chain->present_ids.lock);
|
||||
vk_free(id->alloc, id);
|
||||
@ -2214,29 +2213,30 @@ presentation_handle_presented(void *data,
|
||||
MESA_TRACE_FUNC_FLOW(&id->flow_id);
|
||||
|
||||
struct wsi_wl_swapchain *chain = id->chain;
|
||||
struct wsi_wl_surface *surface = chain->wsi_wl_surface;
|
||||
uint64_t target_time = id->target_time;
|
||||
|
||||
surface->refresh_nsec = refresh;
|
||||
|
||||
presentation_ts.tv_sec = ((uint64_t)tv_sec_hi << 32) + tv_sec_lo;
|
||||
presentation_ts.tv_nsec = tv_nsec;
|
||||
presentation_time = timespec_to_nsec(&presentation_ts);
|
||||
trace_present(id, presentation_time);
|
||||
|
||||
if (!surface->valid_refresh_nsec) {
|
||||
surface->valid_refresh_nsec = true;
|
||||
surface->last_target_time = presentation_time;
|
||||
mtx_lock(&chain->present_ids.lock);
|
||||
chain->present_ids.refresh_nsec = refresh;
|
||||
if (!chain->present_ids.valid_refresh_nsec) {
|
||||
chain->present_ids.valid_refresh_nsec = true;
|
||||
chain->present_ids.last_target_time = presentation_time;
|
||||
target_time = presentation_time;
|
||||
}
|
||||
|
||||
if (presentation_time > surface->displayed_time)
|
||||
surface->displayed_time = presentation_time;
|
||||
if (presentation_time > chain->present_ids.displayed_time)
|
||||
chain->present_ids.displayed_time = presentation_time;
|
||||
|
||||
if (target_time && presentation_time > target_time)
|
||||
surface->display_time_error = presentation_time - target_time;
|
||||
chain->present_ids.display_time_error = presentation_time - target_time;
|
||||
else
|
||||
surface->display_time_error = 0;
|
||||
chain->present_ids.display_time_error = 0;
|
||||
mtx_unlock(&chain->present_ids.lock);
|
||||
|
||||
wsi_wl_presentation_update_present_id(id);
|
||||
wp_presentation_feedback_destroy(feedback);
|
||||
@ -2250,15 +2250,16 @@ presentation_handle_discarded(void *data,
|
||||
|
||||
MESA_TRACE_FUNC_FLOW(&id->flow_id);
|
||||
struct wsi_wl_swapchain *chain = id->chain;
|
||||
struct wsi_wl_surface *surface = chain->wsi_wl_surface;
|
||||
|
||||
if (!surface->valid_refresh_nsec) {
|
||||
mtx_lock(&chain->present_ids.lock);
|
||||
if (!chain->present_ids.valid_refresh_nsec) {
|
||||
/* We've started occluded, so make up some safe values to throttle us */
|
||||
surface->displayed_time = os_time_get_nano();
|
||||
surface->last_target_time = surface->displayed_time;
|
||||
surface->refresh_nsec = 16666666;
|
||||
surface->valid_refresh_nsec = true;
|
||||
chain->present_ids.displayed_time = os_time_get_nano();
|
||||
chain->present_ids.last_target_time = chain->present_ids.displayed_time;
|
||||
chain->present_ids.refresh_nsec = 16666666;
|
||||
chain->present_ids.valid_refresh_nsec = true;
|
||||
}
|
||||
mtx_unlock(&chain->present_ids.lock);
|
||||
|
||||
wsi_wl_presentation_update_present_id(id);
|
||||
wp_presentation_feedback_destroy(feedback);
|
||||
@ -2298,23 +2299,23 @@ static const struct wl_callback_listener frame_listener = {
|
||||
frame_handle_done,
|
||||
};
|
||||
|
||||
/* The present_ids lock must be held */
|
||||
static bool
|
||||
set_timestamp(struct wsi_wl_swapchain *chain,
|
||||
uint64_t *timestamp,
|
||||
uint64_t *correction)
|
||||
{
|
||||
struct wsi_wl_surface *surface = chain->wsi_wl_surface;
|
||||
uint64_t target;
|
||||
struct timespec target_ts;
|
||||
uint64_t refresh;
|
||||
uint64_t displayed_time;
|
||||
int32_t error = 0;
|
||||
|
||||
if (!surface->valid_refresh_nsec)
|
||||
if (!chain->present_ids.valid_refresh_nsec)
|
||||
return false;
|
||||
|
||||
displayed_time = surface->displayed_time;
|
||||
refresh = surface->refresh_nsec;
|
||||
displayed_time = chain->present_ids.displayed_time;
|
||||
refresh = chain->present_ids.refresh_nsec;
|
||||
|
||||
/* If refresh is 0, presentation feedback has informed us we have no
|
||||
* fixed refresh cycle. In that case we can't generate sensible
|
||||
@ -2335,10 +2336,11 @@ set_timestamp(struct wsi_wl_swapchain *chain,
|
||||
* running tally of how much correction we're applying and remove
|
||||
* it as corrected frames are retired.
|
||||
*/
|
||||
if (surface->display_time_error > surface->display_time_correction)
|
||||
error = surface->display_time_error - surface->display_time_correction;
|
||||
if (chain->present_ids.display_time_error > chain->present_ids.display_time_correction)
|
||||
error = chain->present_ids.display_time_error -
|
||||
chain->present_ids.display_time_correction;
|
||||
|
||||
target = surface->last_target_time;
|
||||
target = chain->present_ids.last_target_time;
|
||||
if (error > 0) {
|
||||
target += (error / refresh) * refresh;
|
||||
*correction = (error / refresh) * refresh;
|
||||
@ -2346,7 +2348,7 @@ set_timestamp(struct wsi_wl_swapchain *chain,
|
||||
*correction = 0;
|
||||
}
|
||||
|
||||
surface->display_time_correction += *correction;
|
||||
chain->present_ids.display_time_correction += *correction;
|
||||
target = next_phase_locked_time(displayed_time,
|
||||
refresh,
|
||||
target);
|
||||
@ -2358,7 +2360,7 @@ set_timestamp(struct wsi_wl_swapchain *chain,
|
||||
(uint64_t)target_ts.tv_sec >> 32, target_ts.tv_sec,
|
||||
target_ts.tv_nsec);
|
||||
|
||||
surface->last_target_time = target;
|
||||
chain->present_ids.last_target_time = target;
|
||||
*timestamp = target;
|
||||
return true;
|
||||
}
|
||||
@ -2462,14 +2464,14 @@ wsi_wl_swapchain_queue_present(struct wsi_swapchain *wsi_chain,
|
||||
|
||||
id->submission_time = os_time_get_nano();
|
||||
|
||||
mtx_lock(&chain->present_ids.lock);
|
||||
|
||||
if (mode_fifo && chain->fifo && chain->commit_timer) {
|
||||
timestamped = set_timestamp(chain, &id->target_time, &id->correction);
|
||||
if (timestamped || !wsi_wl_surface->valid_refresh_nsec)
|
||||
if (timestamped || !chain->present_ids.valid_refresh_nsec)
|
||||
need_legacy_throttling = false;
|
||||
}
|
||||
|
||||
mtx_lock(&chain->present_ids.lock);
|
||||
|
||||
if (chain->present_ids.wp_presentation) {
|
||||
id->feedback = wp_presentation_feedback(chain->present_ids.wp_presentation,
|
||||
chain->wsi_wl_surface->surface);
|
||||
@ -3023,6 +3025,9 @@ wsi_wl_surface_create_swapchain(VkIcdSurfaceBase *icd_surface,
|
||||
chain->images[i].busy = false;
|
||||
}
|
||||
|
||||
chain->present_ids.valid_refresh_nsec = false;
|
||||
chain->present_ids.refresh_nsec = 0;
|
||||
|
||||
*swapchain_out = &chain->base;
|
||||
|
||||
return VK_SUCCESS;
|
||||
|
Loading…
Reference in New Issue
Block a user