diff --git a/src/wayland/meta-wayland-presentation-time.c b/src/wayland/meta-wayland-presentation-time.c index 54351690a..be1319fd9 100644 --- a/src/wayland/meta-wayland-presentation-time.c +++ b/src/wayland/meta-wayland-presentation-time.c @@ -26,6 +26,7 @@ #include +#include "compositor/meta-surface-actor-wayland.h" #include "wayland/meta-wayland-private.h" #include "wayland/meta-wayland-surface.h" #include "wayland/meta-wayland-outputs.h" @@ -112,10 +113,8 @@ wp_presentation_bind (struct wl_client *client, } static void -destroy_feedback_list (gpointer data) +discard_feedbacks (struct wl_list *feedbacks) { - struct wl_list *feedbacks = data; - while (!wl_list_empty (feedbacks)) { MetaWaylandPresentationFeedback *feedback = @@ -123,7 +122,67 @@ destroy_feedback_list (gpointer data) meta_wayland_presentation_feedback_discard (feedback); } +} +static void +on_after_paint (ClutterStage *stage, + ClutterStageView *stage_view, + MetaWaylandCompositor *compositor) +{ + struct wl_list *feedbacks; + GList *l; + + /* + * We just painted this stage view, which means that all feedbacks that didn't + * fire (e.g. due to page flip failing) are now obsolete and should be + * discarded. + */ + feedbacks = + meta_wayland_presentation_time_ensure_feedbacks (&compositor->presentation_time, + stage_view); + discard_feedbacks (feedbacks); + + l = compositor->presentation_time.feedback_surfaces; + while (l) + { + GList *l_cur = l; + MetaWaylandSurface *surface = l->data; + MetaSurfaceActor *actor; + ClutterStageView *surface_primary_view; + + l = l->next; + + actor = meta_wayland_surface_get_actor (surface); + if (!actor) + continue; + + surface_primary_view = + meta_surface_actor_wayland_get_current_primary_view (actor, stage); + if (stage_view != surface_primary_view) + continue; + + if (!wl_list_empty (&surface->presentation_time.feedback_list)) + { + /* Add feedbacks to the list to be fired on presentation. */ + wl_list_insert_list (feedbacks, + &surface->presentation_time.feedback_list); + wl_list_init (&surface->presentation_time.feedback_list); + + surface->presentation_time.needs_sequence_update = TRUE; + } + + compositor->presentation_time.feedback_surfaces = + g_list_delete_link (compositor->presentation_time.feedback_surfaces, + l_cur); + } +} + +static void +destroy_feedback_list (gpointer data) +{ + struct wl_list *feedbacks = data; + + discard_feedbacks (feedbacks); g_free (feedbacks); } @@ -141,6 +200,7 @@ meta_wayland_init_presentation_time (MetaWaylandCompositor *compositor) MetaBackend *backend = compositor->backend; MetaMonitorManager *monitor_manager = meta_backend_get_monitor_manager (backend); + ClutterActor *stage = meta_backend_get_stage (backend); compositor->presentation_time.feedbacks = g_hash_table_new_full (NULL, NULL, NULL, destroy_feedback_list); @@ -148,6 +208,9 @@ meta_wayland_init_presentation_time (MetaWaylandCompositor *compositor) g_signal_connect (monitor_manager, "monitors-changed-internal", G_CALLBACK (on_monitors_changed), compositor); + g_signal_connect (stage, "after-paint", + G_CALLBACK (on_after_paint), compositor); + if (wl_global_create (compositor->wayland_display, &wp_presentation_interface, META_WP_PRESENTATION_VERSION, diff --git a/src/wayland/meta-wayland-surface.c b/src/wayland/meta-wayland-surface.c index db0d7f2f3..962ab05ff 100644 --- a/src/wayland/meta-wayland-surface.c +++ b/src/wayland/meta-wayland-surface.c @@ -799,6 +799,10 @@ meta_wayland_surface_apply_state (MetaWaylandSurface *surface, &state->presentation_feedback_list); wl_list_init (&state->presentation_feedback_list); + if (!wl_list_empty (&surface->presentation_time.feedback_list)) + meta_wayland_compositor_add_presentation_feedback_surface (surface->compositor, + surface); + if (surface->role) { meta_wayland_surface_role_apply_state (surface->role, state); @@ -1390,6 +1394,8 @@ wl_surface_destructor (struct wl_resource *resource) cairo_region_destroy (surface->input_region); meta_wayland_compositor_remove_frame_callback_surface (compositor, surface); + meta_wayland_compositor_remove_presentation_feedback_surface (compositor, + surface); g_hash_table_foreach (surface->outputs, surface_output_disconnect_signals, diff --git a/src/wayland/meta-wayland.c b/src/wayland/meta-wayland.c index 731e24727..b032a8bfc 100644 --- a/src/wayland/meta-wayland.c +++ b/src/wayland/meta-wayland.c @@ -230,6 +230,52 @@ on_after_update (ClutterStage *stage, } } +static MetaWaylandOutput * +get_output_for_stage_view (MetaWaylandCompositor *compositor, + ClutterStageView *stage_view) +{ + MetaCrtc *crtc; + MetaOutput *output; + MetaMonitor *monitor; + MetaLogicalMonitor *logical_monitor; + + crtc = meta_renderer_view_get_crtc (META_RENDERER_VIEW (stage_view)); + + /* + * All outputs occupy the same region of the screen, as their contents are + * the same, so pick the first one. + */ + output = meta_crtc_get_outputs (crtc)->data; + + monitor = meta_output_get_monitor (output); + logical_monitor = meta_monitor_get_logical_monitor (monitor); + return g_hash_table_lookup (compositor->outputs, &logical_monitor->winsys_id); +} + +static void +on_presented (ClutterStage *stage, + ClutterStageView *stage_view, + ClutterFrameInfo *frame_info, + MetaWaylandCompositor *compositor) +{ + MetaWaylandPresentationFeedback *feedback, *next; + struct wl_list *feedbacks; + MetaWaylandOutput *output; + + feedbacks = + meta_wayland_presentation_time_ensure_feedbacks (&compositor->presentation_time, + stage_view); + + output = get_output_for_stage_view (compositor, stage_view); + + wl_list_for_each_safe (feedback, next, feedbacks, link) + { + meta_wayland_presentation_feedback_present (feedback, + frame_info, + output); + } +} + /** * meta_wayland_compositor_handle_event: * @compositor: the #MetaWaylandCompositor instance @@ -438,6 +484,8 @@ meta_wayland_compositor_setup (MetaWaylandCompositor *compositor) g_signal_connect (stage, "after-update", G_CALLBACK (on_after_update), compositor); + g_signal_connect (stage, "presented", + G_CALLBACK (on_presented), compositor); if (!wl_global_create (compositor->wayland_display, &wl_compositor_interface,