diff --git a/include/libweston/libweston.h b/include/libweston/libweston.h index b33d8e96d..f36607f29 100644 --- a/include/libweston/libweston.h +++ b/include/libweston/libweston.h @@ -438,6 +438,7 @@ struct weston_output { struct wl_event_source *idle_repaint_source; struct wl_signal frame_signal; + struct wl_signal post_latch_signal; struct wl_signal destroy_signal; /**< sent when disabled */ struct weston_coord_global move; struct timespec frame_time; /* presentation timestamp */ @@ -1493,6 +1494,13 @@ struct weston_compositor { uint32_t placeholder_color; bool no_xwm_decorations; + + /** + * When set the compositor has latched content updates for the + * upcoming repaint, and no more updates may be applied until after + * that repaint occurs. + */ + bool latched; }; struct weston_solid_buffer_values { diff --git a/libweston/compositor.c b/libweston/compositor.c index 2ebcbea13..417e5e7d0 100644 --- a/libweston/compositor.c +++ b/libweston/compositor.c @@ -3615,6 +3615,21 @@ output_assign_planes(struct weston_output *output) } } +/* The "latch" point is the last possible instant before a repaint. After + * the latch, no more content updates can be applied by the compositor + * until after the scheduled repaint completes. + */ +static void +weston_output_latch(struct weston_output *output) +{ + struct weston_compositor *compositor = output->compositor; + + assert(!compositor->latched); + compositor->latched = true; + + wl_signal_emit(&output->post_latch_signal, output); +} + static int weston_output_repaint(struct weston_output *output) { @@ -3628,6 +3643,8 @@ weston_output_repaint(struct weston_output *output) uint32_t frame_time_msec; enum weston_hdcp_protection highest_requested = WESTON_HDCP_DISABLE; + weston_output_latch(output); + TL_POINT(ec, TLP_CORE_REPAINT_BEGIN, TLP_OUTPUT(output), TLP_END); /* Rebuild the surface list and update surface transforms up front. */ @@ -3696,6 +3713,7 @@ weston_output_repaint(struct weston_output *output) output_accumulate_damage(output); r = output->repaint(output); + ec->latched = false; output->repaint_needed = false; if (r == 0) { @@ -8115,6 +8133,7 @@ weston_output_enable(struct weston_output *output) output->original_scale = output->current_scale; wl_signal_init(&output->frame_signal); + wl_signal_init(&output->post_latch_signal); wl_signal_init(&output->destroy_signal); weston_output_transform_scale_init(output, output->transform, diff --git a/libweston/surface-state.c b/libweston/surface-state.c index 19ac44ce0..0f7fc404d 100644 --- a/libweston/surface-state.c +++ b/libweston/surface-state.c @@ -272,6 +272,8 @@ weston_surface_apply_state(struct weston_surface *surface, pixman_region32_t opaque; enum weston_surface_status status = state->status; + assert(!surface->compositor->latched); + surface->flow_id = state->flow_id; state->flow_id = 0; diff --git a/protocol/weston-test.xml b/protocol/weston-test.xml index 717e95dcf..21bd03051 100644 --- a/protocol/weston-test.xml +++ b/protocol/weston-test.xml @@ -99,6 +99,8 @@ + diff --git a/tests/weston-test.c b/tests/weston-test.c index 092f3e500..61167b1d3 100644 --- a/tests/weston-test.c +++ b/tests/weston-test.c @@ -83,6 +83,7 @@ struct weston_test_output { struct weston_test *test; struct weston_output *output; struct wl_listener repaint_listener; + struct wl_listener post_latch_listener; struct wl_list link; }; @@ -138,6 +139,20 @@ output_repaint_listener(struct wl_listener *listener, void *data) } } +static void +output_post_latch_listener(struct wl_listener *listener, void *data) +{ + struct weston_test_output *to = + container_of(listener, struct weston_test_output, + post_latch_listener); + struct weston_head *head; + + wl_list_for_each(head, &to->output->head_list, output_link) { + maybe_breakpoint(to->test, WESTON_TEST_BREAKPOINT_POST_LATCH, + head); + } +} + static void output_created_listener(struct wl_listener *listener, void *data) { @@ -149,8 +164,13 @@ output_created_listener(struct wl_listener *listener, void *data) to->test = test; to->output = output; + to->repaint_listener.notify = output_repaint_listener; wl_signal_add(&output->frame_signal, &to->repaint_listener); + + to->post_latch_listener.notify = output_post_latch_listener; + wl_signal_add(&output->post_latch_signal, &to->post_latch_listener); + wl_list_insert(&test->output_list, &to->link); } @@ -168,6 +188,7 @@ output_destroyed_listener(struct wl_listener *listener, void *data) continue; wl_list_remove(&to->repaint_listener.link); + wl_list_remove(&to->post_latch_listener.link); wl_list_remove(&to->link); free(to); } @@ -883,6 +904,7 @@ out_free: wl_list_for_each_safe(to, tmp, &test->output_list, link) { wl_list_remove(&to->repaint_listener.link); + wl_list_remove(&to->post_latch_listener.link); wl_list_remove(&to->link); free(to); }