Many features, like animations, hardly depend on page flip timestamps to work properly, but some DRM drivers do not correctly support page flip timestamps (or not at all) and in that case, things start to go wrong.
This patch adds sanity check to weston_output_finish_frame. By solely verifying that page flip timestamps are monotonically increasing, we make sure that : 1) Underlying driver is not throwing zeroed-out timestamp series at us. 2) We have not mistakenly jumped backwards because of integer overflow. If a pathological case is detected, we gracefully exit Weston with an appropriate exit code to help developers debug their drivers. This fixes: https://bugs.freedesktop.org/show_bug.cgi?id=79502 Notes: Based on initial design by Pekka Paalanen <[email protected]> Depends on "compositor: Return a user-defined exit code" Signed-off-by: Frederic Plourde <[email protected]> --- src/compositor.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ src/compositor.h | 1 + 2 files changed, 47 insertions(+) diff --git a/src/compositor.c b/src/compositor.c index ac5bda2..c49b3f9 100644 --- a/src/compositor.c +++ b/src/compositor.c @@ -507,6 +507,29 @@ weston_presentation_feedback_present_list(struct wl_list *list, refresh_nsec, ts, seq); } +#define NSEC_PER_SEC 1000000000 + +static int +timespec_cmp(const struct timespec *a, const struct timespec *b) +{ + assert(a->tv_nsec >= 0 && a->tv_nsec < NSEC_PER_SEC); + assert(b->tv_nsec >= 0 && b->tv_nsec < NSEC_PER_SEC); + + if (a->tv_sec < b->tv_sec) + return -1; + + if (a->tv_sec > b->tv_sec) + return 1; + + if (a->tv_nsec < b->tv_nsec) + return -1; + + if (a->tv_nsec > b->tv_nsec) + return 1; + + return 0; +} + static void surface_state_handle_buffer_destroy(struct wl_listener *listener, void *data) { @@ -2052,6 +2075,21 @@ weston_compositor_read_input(int fd, uint32_t mask, void *data) return 1; } +static void +weston_output_check_timestamp(struct weston_output *output, + const struct timespec *cur) +{ + const struct timespec *prev = &output->last_finish_time; + + if (prev->tv_nsec != -1) { + if (timespec_cmp(prev, cur) >= 0) { + weston_log("Bad timestamp! Abort Weston! %m\n"); + weston_compositor_exit_with_code(output->compositor, + EXIT_FAILURE); + } + } +} + WL_EXPORT void weston_output_finish_frame(struct weston_output *output, const struct timespec *stamp) @@ -2062,6 +2100,9 @@ weston_output_finish_frame(struct weston_output *output, int fd, r; uint32_t refresh_nsec; + weston_output_check_timestamp(output, stamp); + output->last_finish_time = *stamp; + refresh_nsec = 1000000000000UL / output->current_mode->refresh; weston_presentation_feedback_present_list(&output->feedback_list, output, refresh_nsec, stamp, @@ -3576,6 +3617,11 @@ weston_output_init(struct weston_output *output, struct weston_compositor *c, output->dirty = 1; output->original_scale = scale; + /* We set tv_nsec out of range here to indicate that we have not + * initialized last_finish_time with a page flip event timestamp yet. + */ + output->last_finish_time.tv_nsec = -1; + weston_output_transform_scale_init(output, transform, scale); weston_output_init_zoom(output); diff --git a/src/compositor.h b/src/compositor.h index a8967f0..d8a2985 100644 --- a/src/compositor.h +++ b/src/compositor.h @@ -205,6 +205,7 @@ struct weston_output { int move_x, move_y; uint32_t frame_time; /* presentation timestamp in milliseconds */ uint64_t msc; /* media stream counter */ + struct timespec last_finish_time; int disable_planes; int destroying; struct wl_list feedback_list; -- 1.9.1 _______________________________________________ wayland-devel mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/wayland-devel
