[PATCH weston v2 09/11] Switch to global output repaint timer
Daniel Stone
daniels at collabora.com
Wed Mar 1 11:34:08 UTC 2017
In preparation for grouping output repaint together where possible,
switch the per-output repaint timer, to a global timer which iterates
across all outputs.
This is implemented by storing the absolute time for the next repaint
for each output locally, and maintaining a global timer which iterates
all of them, scheduling the repaint for the first available time.
Signed-off-by: Daniel Stone <daniels at collabora.com>
Cc: Mario Kleiner <mario.kleiner.de at gmail.com>
Cc: Pekka Paalanen <pekka.paalanen at collabora.co.uk>
---
libweston/compositor.c | 113 ++++++++++++++++++++++++++++++++++++-------------
libweston/compositor.h | 6 ++-
2 files changed, 88 insertions(+), 31 deletions(-)
v2: Rebased on top of previous changes (repaint_status enum).
Suggestions from Pekka:
Keep absolute target repaint time as struct timespec, only using
int64_t nsec for relative comparison to current time, both in
maybe_repaint and finish_frame.
Remove unnecessary output_repaint_timer_arm from schedule_repaint
early-exit path.
Use explict bool rather than 0/~0 time to determine if any outputs
are eligible for repaint in the timer.
diff --git a/libweston/compositor.c b/libweston/compositor.c
index 4aa30da..a64e695 100644
--- a/libweston/compositor.c
+++ b/libweston/compositor.c
@@ -2338,14 +2338,21 @@ weston_output_schedule_repaint_reset(struct weston_output *output)
TL_POINT("core_repaint_exit_loop", TLP_OUTPUT(output), TLP_END);
}
-static int
-output_repaint_timer_handler(void *data)
+static void
+weston_output_maybe_repaint(struct weston_output *output,
+ struct timespec *now)
{
- struct weston_output *output = data;
struct weston_compositor *compositor = output->compositor;
int ret;
+ int64_t msec_to_repaint;
- assert(output->repaint_status == REPAINT_SCHEDULED);
+ /* We're not ready yet; come back to make a decision later. */
+ if (output->repaint_status != REPAINT_SCHEDULED)
+ return;
+
+ msec_to_repaint = timespec_sub_to_msec(&output->next_repaint, now);
+ if (msec_to_repaint > 1)
+ return;
/* If we're sleeping, drop the repaint machinery entirely; we will
* explicitly repaint all outputs when we come back. */
@@ -2360,15 +2367,67 @@ output_repaint_timer_handler(void *data)
/* If repaint fails, we aren't going to get weston_output_finish_frame
* to trigger a new repaint, so drop it from repaint and hope
- * something schedules a successful repaint later. */
+ * something schedules a successful repaint later. As repainting may
+ * take some time, re-read our clock as a courtesy to the next
+ * output. */
ret = weston_output_repaint(output);
+ weston_compositor_read_presentation_clock(compositor, now);
if (ret != 0)
goto err;
- return 0;
+ return;
err:
weston_output_schedule_repaint_reset(output);
+}
+
+static void
+output_repaint_timer_arm(struct weston_compositor *compositor)
+{
+ struct weston_output *output;
+ bool any_should_repaint = false;
+ struct timespec now;
+ int64_t msec_to_next;
+
+ weston_compositor_read_presentation_clock(compositor, &now);
+
+ wl_list_for_each(output, &compositor->output_list, link) {
+ int64_t msec_to_this;
+
+ if (output->repaint_status != REPAINT_SCHEDULED)
+ continue;
+
+ msec_to_this = timespec_sub_to_msec(&output->next_repaint,
+ &now);
+ if (!any_should_repaint || msec_to_this < msec_to_next)
+ msec_to_next = msec_to_this;
+
+ any_should_repaint = true;
+ }
+
+ if (!any_should_repaint)
+ return;
+
+ /* XXX: This can keep postponing forever, maybe? */
+ if (msec_to_next < 1)
+ msec_to_next = 1;
+
+ wl_event_source_timer_update(compositor->repaint_timer, msec_to_next);
+}
+
+static int
+output_repaint_timer_handler(void *data)
+{
+ struct weston_compositor *compositor = data;
+ struct weston_output *output;
+ struct timespec now;
+
+ weston_compositor_read_presentation_clock(compositor, &now);
+ wl_list_for_each(output, &compositor->output_list, link)
+ weston_output_maybe_repaint(output, &now);
+
+ output_repaint_timer_arm(compositor);
+
return 0;
}
@@ -2380,9 +2439,7 @@ weston_output_finish_frame(struct weston_output *output,
struct weston_compositor *compositor = output->compositor;
int32_t refresh_nsec;
struct timespec now;
- struct timespec next;
- struct timespec remain;
- int msec_rel = 0;
+ int64_t msec_rel;
TL_POINT("core_repaint_finished", TLP_OUTPUT(output),
TLP_VBLANK(stamp), TLP_END);
@@ -2390,11 +2447,15 @@ weston_output_finish_frame(struct weston_output *output,
assert(output->repaint_status == REPAINT_AWAITING_COMPLETION);
assert(stamp || (presented_flags & WP_PRESENTATION_FEEDBACK_INVALID));
+ weston_compositor_read_presentation_clock(compositor, &now);
+
/* If we haven't been supplied any timestamp at all, we don't have a
* timebase to work against, so any delay just wastes time. Push a
* repaint as soon as possible so we can get on with it. */
- if (!stamp)
+ if (!stamp) {
+ output->next_repaint = now;
goto out;
+ }
refresh_nsec = millihz_to_nsec(output->current_mode->refresh);
weston_presentation_feedback_present_list(&output->feedback_list,
@@ -2403,22 +2464,21 @@ weston_output_finish_frame(struct weston_output *output,
presented_flags);
output->frame_time = timespec_to_msec(stamp);
- weston_compositor_read_presentation_clock(compositor, &now);
- timespec_add_nsec(&next, stamp, refresh_nsec);
- timespec_add_msec(&next, &next, -compositor->repaint_msec);
- timespec_sub(&remain, &next, &now);
- msec_rel = timespec_to_msec(&remain);
+ timespec_add_nsec(&output->next_repaint, stamp, refresh_nsec);
+ timespec_add_msec(&output->next_repaint, &output->next_repaint,
+ -compositor->repaint_msec);
+ msec_rel = timespec_sub_to_msec(&output->next_repaint, &now);
if (msec_rel < -1000 || msec_rel > 1000) {
static bool warned;
if (!warned)
weston_log("Warning: computed repaint delay is "
- "insane: %d msec\n", msec_rel);
+ "insane: %lld msec\n", (long long) msec_rel);
warned = true;
- msec_rel = 0;
+ output->next_repaint = now;
}
/* Called from restart_repaint_loop and restart happens already after
@@ -2426,15 +2486,12 @@ weston_output_finish_frame(struct weston_output *output,
* the deadline of the next frame, to give clients a more predictable
* timing of the repaint cycle to lock on. */
if (presented_flags == WP_PRESENTATION_FEEDBACK_INVALID && msec_rel < 0)
- msec_rel += refresh_nsec / 1000000;
+ timespec_add_nsec(&output->next_repaint, &output->next_repaint,
+ refresh_nsec);
out:
output->repaint_status = REPAINT_SCHEDULED;
-
- if (msec_rel < 1)
- output_repaint_timer_handler(output);
- else
- wl_event_source_timer_update(output->repaint_timer, msec_rel);
+ output_repaint_timer_arm(compositor);
}
static void
@@ -4425,8 +4482,6 @@ weston_output_transform_coordinate(struct weston_output *output,
static void
weston_output_enable_undo(struct weston_output *output)
{
- wl_event_source_remove(output->repaint_timer);
-
wl_global_destroy(output->global);
pixman_region32_fini(&output->region);
@@ -4608,7 +4663,6 @@ weston_output_enable(struct weston_output *output)
{
struct weston_compositor *c = output->compositor;
struct weston_output *iterator;
- struct wl_event_loop *loop;
int x = 0, y = 0;
assert(output->enable);
@@ -4649,10 +4703,6 @@ weston_output_enable(struct weston_output *output)
wl_list_init(&output->feedback_list);
wl_list_init(&output->link);
- loop = wl_display_get_event_loop(c->wl_display);
- output->repaint_timer = wl_event_loop_add_timer(loop,
- output_repaint_timer_handler, output);
-
/* Invert the output id pool and look for the lowest numbered
* switch (the least significant bit). Take that bit's position
* as our ID, and mark it used in the compositor's output_id_pool.
@@ -5154,6 +5204,9 @@ weston_compositor_create(struct wl_display *display, void *user_data)
loop = wl_display_get_event_loop(ec->wl_display);
ec->idle_source = wl_event_loop_add_timer(loop, idle_handler, ec);
+ ec->repaint_timer =
+ wl_event_loop_add_timer(loop, output_repaint_timer_handler,
+ ec);
weston_layer_init(&ec->fade_layer, ec);
weston_layer_init(&ec->cursor_layer, ec);
diff --git a/libweston/compositor.h b/libweston/compositor.h
index 06a0ff5..93a02ae 100644
--- a/libweston/compositor.h
+++ b/libweston/compositor.h
@@ -182,7 +182,10 @@ struct weston_output {
REPAINT_AWAITING_COMPLETION, /**< last repaint not yet finished */
} repaint_status;
- struct wl_event_source *repaint_timer;
+ /** If repaint_status is REPAINT_SCHEDULED, contains the time the
+ * next repaint should be run */
+ struct timespec next_repaint;
+
struct weston_output_zoom zoom;
int dirty;
struct wl_signal frame_signal;
@@ -855,6 +858,7 @@ struct weston_compositor {
struct wl_event_source *idle_source;
uint32_t idle_inhibit;
int idle_time; /* timeout, s */
+ struct wl_event_source *repaint_timer;
const struct weston_pointer_grab_interface *default_pointer_grab;
--
2.9.3
More information about the wayland-devel
mailing list