From 86df366973de1c10da5fbdc57d1ff12b681c321f Mon Sep 17 00:00:00 2001 From: Roman Gilg Date: Tue, 13 Mar 2018 16:00:54 +0100 Subject: xwayland: Add fallback timer for msc counting When the compositor is not sending frame callbacks while we still wait on buffer release events fake a continuous msc counter with a timer. Having this timer is a prerequisite for queuing events. Signed-off-by: Roman Gilg Reviewed-by: Adam Jackson --- hw/xwayland/xwayland-present.c | 70 ++++++++++++++++++++++++++++++++++++++++++ hw/xwayland/xwayland.h | 3 ++ 2 files changed, 73 insertions(+) diff --git a/hw/xwayland/xwayland-present.c b/hw/xwayland/xwayland-present.c index f41e864b3..a8cc02449 100644 --- a/hw/xwayland/xwayland-present.c +++ b/hw/xwayland/xwayland-present.c @@ -27,6 +27,34 @@ #include +#define TIMER_LEN_FLIP 1000 // 1fps + +static void +xwl_present_free_timer(struct xwl_window *xwl_window) +{ + TimerFree(xwl_window->present_timer); + xwl_window->present_timer = NULL; +} + +static CARD32 +xwl_present_timer_callback(OsTimerPtr timer, + CARD32 time, + void *arg); + +static void +xwl_present_reset_timer(struct xwl_window *xwl_window) +{ + if ( !xorg_list_is_empty(&xwl_window->present_release_queue) ) { + xwl_window->present_timer = TimerSet(xwl_window->present_timer, + 0, + TIMER_LEN_FLIP, + &xwl_present_timer_callback, + xwl_window); + } else { + xwl_present_free_timer(xwl_window); + } +} + void xwl_present_cleanup(WindowPtr window) { @@ -51,6 +79,10 @@ xwl_present_cleanup(WindowPtr window) event->abort = TRUE; } } + + /* Clear timer */ + if ( xorg_list_is_empty(&xwl_window->present_release_queue) ) + xwl_present_free_timer(xwl_window); } static void @@ -90,6 +122,27 @@ static const struct wl_buffer_listener xwl_present_release_listener = { xwl_present_buffer_release }; +CARD32 +xwl_present_timer_callback(OsTimerPtr timer, + CARD32 time, + void *arg) +{ + struct xwl_window *xwl_window = arg; + + xwl_window->present_timer_firing = TRUE; + xwl_window->present_msc++; + xwl_window->present_ust = GetTimeInMicros(); + + if ( !xorg_list_is_empty(&xwl_window->present_release_queue) ) { + /* Still events, restart timer */ + return TIMER_LEN_FLIP; + } else { + /* No more events, do not restart timer and delete it instead */ + xwl_present_free_timer(xwl_window); + return 0; + } +} + static void xwl_present_frame_callback(void *data, struct wl_callback *callback, @@ -100,8 +153,18 @@ xwl_present_frame_callback(void *data, wl_callback_destroy(xwl_window->present_frame_callback); xwl_window->present_frame_callback = NULL; + if (xwl_window->present_timer_firing) { + /* If the timer is firing, this frame callback is too late */ + return; + } + xwl_window->present_msc++; xwl_window->present_ust = GetTimeInMicros(); + + /* we do not need the timer anymore for this frame, + * reset it for potentially the next one + */ + xwl_present_reset_timer(xwl_window); } static const struct wl_callback_listener xwl_present_frame_listener = { @@ -308,6 +371,13 @@ xwl_present_flip(WindowPtr present_window, /* We can flip directly to the main surface (full screen window without clips) */ wl_surface_attach(xwl_window->surface, buffer, 0, 0); + if (!xwl_window->present_timer || + xwl_window->present_timer_firing) { + /* Realign timer */ + xwl_window->present_timer_firing = FALSE; + xwl_present_reset_timer(xwl_window); + } + if (!xwl_window->present_frame_callback) { xwl_window->present_frame_callback = wl_surface_frame(xwl_window->surface); wl_callback_add_listener(xwl_window->present_frame_callback, diff --git a/hw/xwayland/xwayland.h b/hw/xwayland/xwayland.h index dd7d1c685..e6cec18b8 100644 --- a/hw/xwayland/xwayland.h +++ b/hw/xwayland/xwayland.h @@ -135,6 +135,9 @@ struct xwl_window { uint64_t present_msc; uint64_t present_ust; + OsTimerPtr present_timer; + Bool present_timer_firing; + struct wl_callback *present_frame_callback; struct wl_callback *present_sync_callback; struct xorg_list present_release_queue; -- cgit v1.2.3