compositor: set and use the presentation clock everywhere
Add presentation clock setters that verify the given clock actually
works. Offer an automatic choice of a software fallback clock, when a
backend has to always use clock_gettime() to approximate the
presentation time.
The DRM backend already queried the DRM about the clock id, just let the
DRM backend set the presentation clock from that.
For all other backends which do not get a timestamp from the driver,
call the software clock setter to choose a suitable clock.
Report the chosen clock via presentation.clock_id event to clients.
In finish_frame(), upgrade the argument from uint32_t milliseconds to
struct timespec which can accurately hold the presentation clock values.
This will be needed when weston_output_finish_frame() starts to send out
presentation_feedback.presented events.
While at it, replace gettimeofday() calls with clock_gettime() using the
chosen presentation clock, so we manufacture presentation timestamps
from the presentation clock when the gfx drivers cannot give us a proper
timestamp.
Rpi patch is more verbose due to not having the compositor pointer
available in rpi_flippipe_update_complete(). Explicitly carry the clock
id with flippipe so it is available in the thread.
Changes in v4:
* rpi debug build fix
v4 Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
v3 Reviewed-by: Mario Kleiner <mario.kleiner.de@gmail.com>
diff --git a/src/compositor.c b/src/compositor.c
index d789508..f34d712 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -1896,7 +1896,7 @@
}
static int
-weston_output_repaint(struct weston_output *output, uint32_t msecs)
+weston_output_repaint(struct weston_output *output)
{
struct weston_compositor *ec = output->compositor;
struct weston_view *ev;
@@ -1951,13 +1951,13 @@
wl_event_loop_dispatch(ec->input_loop, 0);
wl_list_for_each_safe(cb, cnext, &frame_callback_list, link) {
- wl_callback_send_done(cb->resource, msecs);
+ wl_callback_send_done(cb->resource, output->frame_time);
wl_resource_destroy(cb->resource);
}
wl_list_for_each_safe(animation, next, &output->animation_list, link) {
animation->frame_counter++;
- animation->frame(animation, output, msecs);
+ animation->frame(animation, output, output->frame_time);
}
return r;
@@ -1974,19 +1974,20 @@
}
WL_EXPORT void
-weston_output_finish_frame(struct weston_output *output, uint32_t msecs)
+weston_output_finish_frame(struct weston_output *output,
+ const struct timespec *stamp)
{
struct weston_compositor *compositor = output->compositor;
struct wl_event_loop *loop =
wl_display_get_event_loop(compositor->wl_display);
int fd, r;
- output->frame_time = msecs;
+ output->frame_time = stamp->tv_sec * 1000 + stamp->tv_nsec / 1000000;
if (output->repaint_needed &&
compositor->state != WESTON_COMPOSITOR_SLEEPING &&
compositor->state != WESTON_COMPOSITOR_OFFSCREEN) {
- r = weston_output_repaint(output, msecs);
+ r = weston_output_repaint(output);
if (!r)
return;
}
@@ -3773,7 +3774,7 @@
wl_resource_set_implementation(resource, &presentation_implementation,
compositor, NULL);
- presentation_send_clock_id(resource, CLOCK_MONOTONIC);
+ presentation_send_clock_id(resource, compositor->presentation_clock);
}
static void
@@ -3974,6 +3975,48 @@
}
}
+WL_EXPORT int
+weston_compositor_set_presentation_clock(struct weston_compositor *compositor,
+ clockid_t clk_id)
+{
+ struct timespec ts;
+
+ if (clock_gettime(clk_id, &ts) < 0)
+ return -1;
+
+ compositor->presentation_clock = clk_id;
+
+ return 0;
+}
+
+/*
+ * For choosing the software clock, when the display hardware or API
+ * does not expose a compatible presentation timestamp.
+ */
+WL_EXPORT int
+weston_compositor_set_presentation_clock_software(
+ struct weston_compositor *compositor)
+{
+ /* In order of preference */
+ static const clockid_t clocks[] = {
+ CLOCK_MONOTONIC_RAW, /* no jumps, no crawling */
+ CLOCK_MONOTONIC_COARSE, /* no jumps, may crawl, fast & coarse */
+ CLOCK_MONOTONIC, /* no jumps, may crawl */
+ CLOCK_REALTIME_COARSE, /* may jump and crawl, fast & coarse */
+ CLOCK_REALTIME /* may jump and crawl */
+ };
+ unsigned i;
+
+ for (i = 0; i < ARRAY_LENGTH(clocks); i++)
+ if (weston_compositor_set_presentation_clock(compositor,
+ clocks[i]) == 0)
+ return 0;
+
+ weston_log("Error: no suitable presentation clock available.\n");
+
+ return -1;
+}
+
WL_EXPORT void
weston_version(int *major, int *minor, int *micro)
{
@@ -3982,6 +4025,24 @@
*micro = WESTON_VERSION_MICRO;
}
+static const char *
+clock_name(clockid_t clk_id)
+{
+ static const char *names[] = {
+ [CLOCK_REALTIME] = "CLOCK_REALTIME",
+ [CLOCK_MONOTONIC] = "CLOCK_MONOTONIC",
+ [CLOCK_MONOTONIC_RAW] = "CLOCK_MONOTONIC_RAW",
+ [CLOCK_REALTIME_COARSE] = "CLOCK_REALTIME_COARSE",
+ [CLOCK_MONOTONIC_COARSE] = "CLOCK_MONOTONIC_COARSE",
+ [CLOCK_BOOTTIME] = "CLOCK_BOOTTIME",
+ };
+
+ if (clk_id < 0 || (unsigned)clk_id >= ARRAY_LENGTH(names))
+ return "unknown";
+
+ return names[clk_id];
+}
+
static const struct {
uint32_t bit; /* enum weston_capability */
const char *desc;
@@ -4003,6 +4064,10 @@
capability_strings[i].desc,
yes ? "yes" : "no");
}
+
+ weston_log_continue(STAMP_SPACE "presentation clock: %s, id %d\n",
+ clock_name(compositor->presentation_clock),
+ compositor->presentation_clock);
}
static int on_term_signal(int signal_number, void *data)