From b891f8a52c54280cbaed1d163eac154b67a3a2be Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Thu, 15 Sep 2022 00:30:23 +0200 Subject: [PATCH] compositor: Move frame drawn x11 management to MetaSyncCounter This is part of the same MetaSyncCounter mechanism, so move it together on one place. Part-of: --- src/compositor/meta-window-actor-x11.c | 282 +++---------------------- src/x11/meta-sync-counter.c | 265 ++++++++++++++++++++++- src/x11/meta-sync-counter.h | 20 ++ 3 files changed, 312 insertions(+), 255 deletions(-) diff --git a/src/compositor/meta-window-actor-x11.c b/src/compositor/meta-window-actor-x11.c index 6791bac5f..de0cb9219 100644 --- a/src/compositor/meta-window-actor-x11.c +++ b/src/compositor/meta-window-actor-x11.c @@ -41,6 +41,7 @@ #include "meta/meta-x11-errors.h" #include "meta/window.h" #include "x11/window-x11.h" +#include "x11/meta-sync-counter.h" #include "x11/meta-x11-display-private.h" #include "x11/window-x11.h" @@ -54,19 +55,12 @@ struct _MetaWindowActorX11 { MetaWindowActor parent; - /* List of FrameData for recent frames */ - GList *frames; - guint send_frame_messages_timer; - int64_t frame_drawn_time; gboolean pending_schedule_update_now; gulong repaint_scheduled_id; gulong size_changed_id; - /* If set, the client needs to be sent a _NET_WM_FRAME_DRAWN - * client message for one or more messages in ->frames */ - gboolean needs_frame_drawn; gboolean repaint_scheduled; /* @@ -111,30 +105,6 @@ static void cullable_iface_init (MetaCullableInterface *iface); G_DEFINE_TYPE_WITH_CODE (MetaWindowActorX11, meta_window_actor_x11, META_TYPE_WINDOW_ACTOR, G_IMPLEMENT_INTERFACE (META_TYPE_CULLABLE, cullable_iface_init)) -/* Each time the application updates the sync request counter to a new even value - * value, we queue a frame into the windows list of frames. Once we're painting - * an update "in response" to the window, we fill in frame_counter with the - * Cogl counter for that frame, and send _NET_WM_FRAME_DRAWN at the end of the - * frame. _NET_WM_FRAME_TIMINGS is sent when we get a frame_complete callback. - * - * As an exception, if a window is completely obscured, we try to throttle drawning - * to a slower frame rate. In this case, frame_counter stays -1 until - * send_frame_message_timeout() runs, at which point we send both the - * _NET_WM_FRAME_DRAWN and _NET_WM_FRAME_TIMINGS messages. - */ -typedef struct -{ - uint64_t sync_request_serial; - int64_t frame_counter; - int64_t frame_drawn_time; -} FrameData; - -static void -frame_data_free (FrameData *frame) -{ - g_free (frame); -} - static void surface_repaint_scheduled (MetaSurfaceActor *actor, gpointer user_data) @@ -152,165 +122,16 @@ remove_frame_messages_timer (MetaWindowActorX11 *actor_x11) g_clear_handle_id (&actor_x11->send_frame_messages_timer, g_source_remove); } -static void -do_send_frame_drawn (MetaWindowActorX11 *actor_x11, - FrameData *frame) -{ - MetaWindow *window = - meta_window_actor_get_meta_window (META_WINDOW_ACTOR (actor_x11)); - MetaDisplay *display = meta_window_get_display (window); - Display *xdisplay = meta_x11_display_get_xdisplay (display->x11_display); - int64_t now_us; - - XClientMessageEvent ev = { 0, }; - - COGL_TRACE_BEGIN (MetaWindowActorX11FrameDrawn, - "X11: Send _NET_WM_FRAME_DRAWN"); - - now_us = g_get_monotonic_time (); - frame->frame_drawn_time = - meta_compositor_monotonic_to_high_res_xserver_time (display->compositor, - now_us); - actor_x11->frame_drawn_time = frame->frame_drawn_time; - - ev.type = ClientMessage; - ev.window = meta_window_get_xwindow (window); - ev.message_type = display->x11_display->atom__NET_WM_FRAME_DRAWN; - ev.format = 32; - ev.data.l[0] = frame->sync_request_serial & G_GUINT64_CONSTANT (0xffffffff); - ev.data.l[1] = frame->sync_request_serial >> 32; - ev.data.l[2] = frame->frame_drawn_time & G_GUINT64_CONSTANT (0xffffffff); - ev.data.l[3] = frame->frame_drawn_time >> 32; - - meta_x11_error_trap_push (display->x11_display); - XSendEvent (xdisplay, ev.window, False, 0, (XEvent *) &ev); - XFlush (xdisplay); - meta_x11_error_trap_pop (display->x11_display); - -#ifdef COGL_HAS_TRACING - if (G_UNLIKELY (cogl_is_tracing_enabled ())) - { - g_autofree char *description = NULL; - - description = g_strdup_printf ("frame drawn time: %" G_GINT64_FORMAT ", " - "sync request serial: %" G_GINT64_FORMAT, - frame->frame_drawn_time, - frame->sync_request_serial); - COGL_TRACE_DESCRIBE (MetaWindowActorX11FrameDrawn, - description); - COGL_TRACE_END (MetaWindowActorX11FrameDrawn); - } -#endif -} - -static void -do_send_frame_timings (MetaWindowActorX11 *actor_x11, - FrameData *frame, - int refresh_interval, - int64_t presentation_time) -{ - MetaWindow *window = - meta_window_actor_get_meta_window (META_WINDOW_ACTOR (actor_x11)); - MetaDisplay *display = meta_window_get_display (window); - Display *xdisplay = meta_x11_display_get_xdisplay (display->x11_display); - - XClientMessageEvent ev = { 0, }; - - COGL_TRACE_BEGIN (MetaWindowActorX11FrameTimings, - "X11: Send _NET_WM_FRAME_TIMINGS"); - - ev.type = ClientMessage; - ev.window = meta_window_get_xwindow (window); - ev.message_type = display->x11_display->atom__NET_WM_FRAME_TIMINGS; - ev.format = 32; - ev.data.l[0] = frame->sync_request_serial & G_GUINT64_CONSTANT (0xffffffff); - ev.data.l[1] = frame->sync_request_serial >> 32; - - if (presentation_time != 0) - { - MetaCompositor *compositor = display->compositor; - int64_t presentation_time_server; - - presentation_time_server = - meta_compositor_monotonic_to_high_res_xserver_time (compositor, - presentation_time); - int64_t presentation_time_offset = presentation_time_server - frame->frame_drawn_time; - if (presentation_time_offset == 0) - presentation_time_offset = 1; - - if ((int32_t)presentation_time_offset == presentation_time_offset) - ev.data.l[2] = presentation_time_offset; - } - - ev.data.l[3] = refresh_interval; - ev.data.l[4] = 1000 * META_SYNC_DELAY; - - meta_x11_error_trap_push (display->x11_display); - XSendEvent (xdisplay, ev.window, False, 0, (XEvent *) &ev); - XFlush (xdisplay); - meta_x11_error_trap_pop (display->x11_display); - -#ifdef COGL_HAS_TRACING - if (G_UNLIKELY (cogl_is_tracing_enabled ())) - { - g_autofree char *description = NULL; - - description = - g_strdup_printf ("refresh interval: %d, " - "presentation time: %" G_GINT64_FORMAT ", " - "sync request serial: %" G_GINT64_FORMAT, - refresh_interval, - frame->sync_request_serial, - presentation_time); - COGL_TRACE_DESCRIBE (MetaWindowActorX11FrameTimings, description); - COGL_TRACE_END (MetaWindowActorX11FrameTimings); - } -#endif -} - -static void -send_frame_timings (MetaWindowActorX11 *actor_x11, - FrameData *frame, - ClutterFrameInfo *frame_info, - int64_t presentation_time) -{ - float refresh_rate; - int refresh_interval; - - refresh_rate = frame_info->refresh_rate; - /* 0.0 is a flag for not known, but sanity-check against other odd numbers */ - if (refresh_rate >= 1.0) - refresh_interval = (int) (0.5 + 1000000 / refresh_rate); - else - refresh_interval = 0; - - do_send_frame_timings (actor_x11, frame, refresh_interval, presentation_time); -} - static gboolean send_frame_messages_timeout (gpointer data) { MetaWindowActorX11 *actor_x11 = META_WINDOW_ACTOR_X11 (data); - GList *l; + MetaWindow *window = + meta_window_actor_get_meta_window (META_WINDOW_ACTOR (actor_x11)); + MetaSyncCounter *sync_counter; - for (l = actor_x11->frames; l;) - { - GList *l_next = l->next; - FrameData *frame = l->data; - - if (frame->frame_counter == -1) - { - do_send_frame_drawn (actor_x11, frame); - do_send_frame_timings (actor_x11, frame, 0, 0); - - actor_x11->frames = g_list_delete_link (actor_x11->frames, l); - frame_data_free (frame); - } - - l = l_next; - } - - actor_x11->needs_frame_drawn = FALSE; + sync_counter = meta_window_x11_get_sync_counter (window); + meta_sync_counter_finish_incomplete (sync_counter); actor_x11->send_frame_messages_timer = 0; return G_SOURCE_REMOVE; @@ -323,6 +144,7 @@ queue_send_frame_messages_timeout (MetaWindowActorX11 *actor_x11) meta_window_actor_get_meta_window (META_WINDOW_ACTOR (actor_x11)); MetaDisplay *display = meta_window_get_display (window); MetaLogicalMonitor *logical_monitor; + MetaSyncCounter *sync_counter; int64_t now_us; int64_t current_time; float refresh_rate; @@ -353,7 +175,8 @@ queue_send_frame_messages_timeout (MetaWindowActorX11 *actor_x11) meta_compositor_monotonic_to_high_res_xserver_time (display->compositor, now_us); interval = (int) (1000000 / refresh_rate) * 6; - offset = MAX (0, actor_x11->frame_drawn_time + interval - current_time) / 1000; + sync_counter = meta_window_x11_get_sync_counter (window); + offset = MAX (0, sync_counter->frame_drawn_time + interval - current_time) / 1000; /* The clutter master clock source has already been added with META_PRIORITY_REDRAW, * so the timer will run *after* the clutter frame handling, if a frame is ready @@ -374,7 +197,7 @@ assign_frame_counter_to_frames (MetaWindowActorX11 *actor_x11) meta_window_actor_get_meta_window (META_WINDOW_ACTOR (actor_x11)); MetaCompositor *compositor = window->display->compositor; ClutterStage *stage = meta_compositor_get_stage (compositor); - GList *l; + MetaSyncCounter *sync_counter; /* If the window is obscured, then we're expecting to deal with sending * frame messages in a timeout, rather than in this paint cycle. @@ -382,13 +205,9 @@ assign_frame_counter_to_frames (MetaWindowActorX11 *actor_x11) if (actor_x11->send_frame_messages_timer != 0) return; - for (l = actor_x11->frames; l; l = l->next) - { - FrameData *frame = l->data; - - if (frame->frame_counter == -1) - frame->frame_counter = clutter_stage_get_frame_counter (stage); - } + sync_counter = meta_window_x11_get_sync_counter (window); + meta_sync_counter_assign_counter_to_frames (sync_counter, + clutter_stage_get_frame_counter (stage)); } static void @@ -396,37 +215,16 @@ meta_window_actor_x11_frame_complete (MetaWindowActor *actor, ClutterFrameInfo *frame_info, int64_t presentation_time) { - MetaWindowActorX11 *actor_x11 = META_WINDOW_ACTOR_X11 (actor); - GList *l; + MetaWindow *window = meta_window_actor_get_meta_window (actor); + MetaSyncCounter *sync_counter; if (meta_window_actor_is_destroyed (actor)) return; - for (l = actor_x11->frames; l;) - { - GList *l_next = l->next; - FrameData *frame = l->data; - int64_t frame_counter = frame_info->frame_counter; - - if (frame->frame_counter != -1 && frame->frame_counter <= frame_counter) - { - MetaWindow *window = - meta_window_actor_get_meta_window (actor); - - if (G_UNLIKELY (frame->frame_drawn_time == 0)) - g_warning ("%s: Frame has assigned frame counter but no frame drawn time", - window->desc); - if (G_UNLIKELY (frame->frame_counter < frame_counter)) - g_debug ("%s: frame_complete callback never occurred for frame %" G_GINT64_FORMAT, - window->desc, frame->frame_counter); - - actor_x11->frames = g_list_delete_link (actor_x11->frames, l); - send_frame_timings (actor_x11, frame, frame_info, presentation_time); - frame_data_free (frame); - } - - l = l_next; - } + sync_counter = meta_window_x11_get_sync_counter (window); + meta_sync_counter_complete_frame (sync_counter, + frame_info, + presentation_time); } static MetaSurfaceActor * @@ -499,23 +297,10 @@ meta_window_actor_x11_queue_frame_drawn (MetaWindowActor *actor, gboolean skip_sync_delay) { MetaWindowActorX11 *actor_x11 = META_WINDOW_ACTOR_X11 (actor); - MetaWindow *window = - meta_window_actor_get_meta_window (actor); - MetaSyncCounter *sync_counter = - meta_window_x11_get_sync_counter (window); - FrameData *frame; if (meta_window_actor_is_destroyed (actor)) return; - frame = g_new0 (FrameData, 1); - frame->frame_counter = -1; - frame->sync_request_serial = sync_counter->sync_request_serial; - - actor_x11->frames = g_list_prepend (actor_x11->frames, frame); - - actor_x11->needs_frame_drawn = TRUE; - if (skip_sync_delay) { ClutterFrameClock *frame_clock; @@ -1404,6 +1189,7 @@ meta_window_actor_x11_after_paint (MetaWindowActor *actor, ClutterStageView *stage_view) { MetaWindowActorX11 *actor_x11 = META_WINDOW_ACTOR_X11 (actor); + MetaSyncCounter *sync_counter; MetaWindow *window; actor_x11->repaint_scheduled = FALSE; @@ -1411,28 +1197,19 @@ meta_window_actor_x11_after_paint (MetaWindowActor *actor, if (meta_window_actor_is_destroyed (actor)) return; + window = meta_window_actor_get_meta_window (actor); + /* If the window had damage, but wasn't actually redrawn because * it is obscured, we should wait until timer expiration before * sending _NET_WM_FRAME_* messages. */ - if (actor_x11->send_frame_messages_timer == 0 && - actor_x11->needs_frame_drawn) + if (actor_x11->send_frame_messages_timer == 0) { - GList *l; - - for (l = actor_x11->frames; l; l = l->next) - { - FrameData *frame = l->data; - - if (frame->frame_drawn_time == 0) - do_send_frame_drawn (actor_x11, frame); - } - - actor_x11->needs_frame_drawn = FALSE; + sync_counter = meta_window_x11_get_sync_counter (window); + meta_sync_counter_send_frame_drawn (sync_counter); } /* This is for Xwayland, and a no-op on plain Xorg */ - window = meta_window_actor_get_meta_window (actor); if (meta_window_x11_should_thaw_after_paint (window)) { meta_window_x11_thaw_commits (window); @@ -1631,7 +1408,10 @@ meta_window_actor_x11_constructed (GObject *object) */ if (sync_counter->extended_sync_request_counter && !meta_window_updates_are_frozen (window)) - meta_window_actor_queue_frame_drawn (actor, FALSE); + { + meta_sync_counter_queue_frame_drawn (sync_counter); + meta_window_actor_queue_frame_drawn (actor, FALSE); + } } static void @@ -1702,10 +1482,6 @@ meta_window_actor_x11_dispose (GObject *object) static void meta_window_actor_x11_finalize (GObject *object) { - MetaWindowActorX11 *actor_x11 = META_WINDOW_ACTOR_X11 (object); - - g_list_free_full (actor_x11->frames, (GDestroyNotify) frame_data_free); - G_OBJECT_CLASS (meta_window_actor_x11_parent_class)->finalize (object); } diff --git a/src/x11/meta-sync-counter.c b/src/x11/meta-sync-counter.c index b05f35a24..610035248 100644 --- a/src/x11/meta-sync-counter.c +++ b/src/x11/meta-sync-counter.c @@ -21,10 +21,29 @@ #include "meta-sync-counter.h" +#include "compositor/compositor-private.h" #include "core/window-private.h" #include "meta/meta-x11-errors.h" #include "x11/meta-x11-display-private.h" +/* Each time the application updates the sync request counter to a new even value + * value, we queue a frame into the windows list of frames. Once we're painting + * an update "in response" to the window, we fill in frame_counter with the + * Cogl counter for that frame, and send _NET_WM_FRAME_DRAWN at the end of the + * frame. _NET_WM_FRAME_TIMINGS is sent when we get a frame_complete callback. + * + * As an exception, if a window is completely obscured, we try to throttle drawning + * to a slower frame rate. In this case, frame_counter stays -1 until + * send_frame_message_timeout() runs, at which point we send both the + * _NET_WM_FRAME_DRAWN and _NET_WM_FRAME_TIMINGS messages. + */ +typedef struct +{ + uint64_t sync_request_serial; + int64_t frame_counter; + int64_t frame_drawn_time; +} FrameData; + void meta_sync_counter_init (MetaSyncCounter *sync_counter, MetaWindow *window, @@ -39,6 +58,7 @@ meta_sync_counter_clear (MetaSyncCounter *sync_counter) { g_clear_handle_id (&sync_counter->sync_request_timeout_id, g_source_remove); meta_sync_counter_destroy_sync_alarm (sync_counter); + g_clear_list (&sync_counter->frames, g_free); sync_counter->window = NULL; sync_counter->xwindow = None; } @@ -310,8 +330,11 @@ meta_sync_counter_update (MetaSyncCounter *sync_counter, sync_counter->disabled = FALSE; if (needs_frame_drawn) - meta_compositor_queue_frame_drawn (window->display->compositor, window, - no_delay_frame); + { + meta_sync_counter_queue_frame_drawn (sync_counter); + meta_compositor_queue_frame_drawn (window->display->compositor, window, + no_delay_frame); + } #ifdef COGL_HAS_TRACING if (G_UNLIKELY (cogl_is_tracing_enabled ())) @@ -347,3 +370,241 @@ meta_sync_counter_is_waiting_response (MetaSyncCounter *sync_counter) { return sync_counter->sync_request_timeout_id != 0; } + +static void +do_send_frame_drawn (MetaSyncCounter *sync_counter, + FrameData *frame) +{ + MetaWindow *window = sync_counter->window; + MetaDisplay *display = meta_window_get_display (window); + Display *xdisplay = meta_x11_display_get_xdisplay (display->x11_display); + int64_t now_us; + XClientMessageEvent ev = { 0, }; + + COGL_TRACE_BEGIN (MetaWindowActorX11FrameDrawn, + "X11: Send _NET_WM_FRAME_DRAWN"); + + now_us = g_get_monotonic_time (); + frame->frame_drawn_time = + meta_compositor_monotonic_to_high_res_xserver_time (display->compositor, + now_us); + sync_counter->frame_drawn_time = frame->frame_drawn_time; + + ev.type = ClientMessage; + ev.window = sync_counter->xwindow; + ev.message_type = display->x11_display->atom__NET_WM_FRAME_DRAWN; + ev.format = 32; + ev.data.l[0] = frame->sync_request_serial & G_GUINT64_CONSTANT (0xffffffff); + ev.data.l[1] = frame->sync_request_serial >> 32; + ev.data.l[2] = frame->frame_drawn_time & G_GUINT64_CONSTANT (0xffffffff); + ev.data.l[3] = frame->frame_drawn_time >> 32; + + meta_x11_error_trap_push (display->x11_display); + XSendEvent (xdisplay, ev.window, False, 0, (XEvent *) &ev); + XFlush (xdisplay); + meta_x11_error_trap_pop (display->x11_display); + +#ifdef COGL_HAS_TRACING + if (G_UNLIKELY (cogl_is_tracing_enabled ())) + { + g_autofree char *description = NULL; + + description = g_strdup_printf ("frame drawn time: %" G_GINT64_FORMAT ", " + "sync request serial: %" G_GINT64_FORMAT, + frame->frame_drawn_time, + frame->sync_request_serial); + COGL_TRACE_DESCRIBE (MetaWindowActorX11FrameDrawn, + description); + COGL_TRACE_END (MetaWindowActorX11FrameDrawn); + } +#endif +} + +static void +do_send_frame_timings (MetaSyncCounter *sync_counter, + FrameData *frame, + int refresh_interval, + int64_t presentation_time) +{ + MetaWindow *window = sync_counter->window; + MetaDisplay *display = meta_window_get_display (window); + Display *xdisplay = meta_x11_display_get_xdisplay (display->x11_display); + XClientMessageEvent ev = { 0, }; + + COGL_TRACE_BEGIN (MetaWindowActorX11FrameTimings, + "X11: Send _NET_WM_FRAME_TIMINGS"); + + ev.type = ClientMessage; + ev.window = sync_counter->xwindow; + ev.message_type = display->x11_display->atom__NET_WM_FRAME_TIMINGS; + ev.format = 32; + ev.data.l[0] = frame->sync_request_serial & G_GUINT64_CONSTANT (0xffffffff); + ev.data.l[1] = frame->sync_request_serial >> 32; + + if (presentation_time != 0) + { + MetaCompositor *compositor = display->compositor; + int64_t presentation_time_server, presentation_time_offset; + + presentation_time_server = + meta_compositor_monotonic_to_high_res_xserver_time (compositor, + presentation_time); + presentation_time_offset = presentation_time_server - frame->frame_drawn_time; + if (presentation_time_offset == 0) + presentation_time_offset = 1; + + if ((int32_t) presentation_time_offset == presentation_time_offset) + ev.data.l[2] = presentation_time_offset; + } + + ev.data.l[3] = refresh_interval; + ev.data.l[4] = 1000 * META_SYNC_DELAY; + + meta_x11_error_trap_push (display->x11_display); + XSendEvent (xdisplay, ev.window, False, 0, (XEvent *) &ev); + XFlush (xdisplay); + meta_x11_error_trap_pop (display->x11_display); + +#ifdef COGL_HAS_TRACING + if (G_UNLIKELY (cogl_is_tracing_enabled ())) + { + g_autofree char *description = NULL; + + description = + g_strdup_printf ("refresh interval: %d, " + "presentation time: %" G_GINT64_FORMAT ", " + "sync request serial: %" G_GINT64_FORMAT, + refresh_interval, + frame->sync_request_serial, + presentation_time); + COGL_TRACE_DESCRIBE (MetaWindowActorX11FrameTimings, description); + COGL_TRACE_END (MetaWindowActorX11FrameTimings); + } +#endif +} + +static void +send_frame_timings (MetaSyncCounter *sync_counter, + FrameData *frame, + ClutterFrameInfo *frame_info, + int64_t presentation_time) +{ + float refresh_rate; + int refresh_interval; + + refresh_rate = frame_info->refresh_rate; + /* 0.0 is a flag for not known, but sanity-check against other odd numbers */ + if (refresh_rate >= 1.0) + refresh_interval = (int) (0.5 + 1000000 / refresh_rate); + else + refresh_interval = 0; + + do_send_frame_timings (sync_counter, frame, + refresh_interval, presentation_time); +} + +void +meta_sync_counter_queue_frame_drawn (MetaSyncCounter *sync_counter) +{ + FrameData *frame; + + frame = g_new0 (FrameData, 1); + frame->frame_counter = -1; + frame->sync_request_serial = sync_counter->sync_request_serial; + + sync_counter->frames = g_list_prepend (sync_counter->frames, frame); + + sync_counter->needs_frame_drawn = TRUE; +} + +void +meta_sync_counter_assign_counter_to_frames (MetaSyncCounter *sync_counter, + int64_t counter) +{ + GList *l; + + for (l = sync_counter->frames; l; l = l->next) + { + FrameData *frame = l->data; + + if (frame->frame_counter == -1) + frame->frame_counter = counter; + } +} + +void +meta_sync_counter_complete_frame (MetaSyncCounter *sync_counter, + ClutterFrameInfo *frame_info, + int64_t presentation_time) +{ + GList *l; + + for (l = sync_counter->frames; l;) + { + GList *l_next = l->next; + FrameData *frame = l->data; + int64_t frame_counter = frame_info->frame_counter; + + if (frame->frame_counter != -1 && frame->frame_counter <= frame_counter) + { + MetaWindow *window = sync_counter->window; + + if (G_UNLIKELY (frame->frame_drawn_time == 0)) + g_warning ("%s: Frame has assigned frame counter but no frame drawn time", + window->desc); + if (G_UNLIKELY (frame->frame_counter < frame_counter)) + g_debug ("%s: frame_complete callback never occurred for frame %" G_GINT64_FORMAT, + window->desc, frame->frame_counter); + + sync_counter->frames = g_list_delete_link (sync_counter->frames, l); + send_frame_timings (sync_counter, frame, frame_info, presentation_time); + g_free (frame); + } + + l = l_next; + } +} + +void +meta_sync_counter_finish_incomplete (MetaSyncCounter *sync_counter) +{ + GList *l; + + for (l = sync_counter->frames; l;) + { + GList *l_next = l->next; + FrameData *frame = l->data; + + if (frame->frame_counter == -1) + { + do_send_frame_drawn (sync_counter, frame); + do_send_frame_timings (sync_counter, frame, 0, 0); + + sync_counter->frames = g_list_delete_link (sync_counter->frames, l); + g_free (frame); + } + + l = l_next; + } + + sync_counter->needs_frame_drawn = FALSE; +} + +void +meta_sync_counter_send_frame_drawn (MetaSyncCounter *sync_counter) +{ + GList *l; + + if (!sync_counter->needs_frame_drawn) + return; + + for (l = sync_counter->frames; l; l = l->next) + { + FrameData *frame = l->data; + + if (frame->frame_drawn_time == 0) + do_send_frame_drawn (sync_counter, frame); + } + + sync_counter->needs_frame_drawn = FALSE; +} diff --git a/src/x11/meta-sync-counter.h b/src/x11/meta-sync-counter.h index 364bea1e6..a831570c0 100644 --- a/src/x11/meta-sync-counter.h +++ b/src/x11/meta-sync-counter.h @@ -36,10 +36,17 @@ typedef struct guint sync_request_timeout_id; /* alarm monitoring client's _NET_WM_SYNC_REQUEST_COUNTER */ XSyncAlarm sync_request_alarm; + + int64_t frame_drawn_time; + GList *frames; + /* if TRUE, the we have the new form of sync request counter which * also handles application frames */ guint extended_sync_request_counter : 1; guint disabled : 1; + /* If set, the client needs to be sent a _NET_WM_FRAME_DRAWN + * client message for one or more messages in ->frames */ + guint needs_frame_drawn : 1; } MetaSyncCounter; void meta_sync_counter_init (MetaSyncCounter *sync_counter, @@ -67,4 +74,17 @@ gboolean meta_sync_counter_is_waiting (MetaSyncCounter *sync_counter); gboolean meta_sync_counter_is_waiting_response (MetaSyncCounter *sync_counter); +void meta_sync_counter_queue_frame_drawn (MetaSyncCounter *sync_counter); + +void meta_sync_counter_assign_counter_to_frames (MetaSyncCounter *sync_counter, + int64_t counter); + +void meta_sync_counter_complete_frame (MetaSyncCounter *sync_counter, + ClutterFrameInfo *frame_info, + int64_t presentation_time); + +void meta_sync_counter_finish_incomplete (MetaSyncCounter *sync_counter); + +void meta_sync_counter_send_frame_drawn (MetaSyncCounter *sync_counter); + #endif /* META_SYNC_COUNTER_H */