summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarlos Garnacho <carlosg@gnome.org>2022-09-15 00:30:23 +0200
committerMarge Bot <marge-bot@gnome.org>2022-12-01 20:10:52 +0000
commitb891f8a52c54280cbaed1d163eac154b67a3a2be (patch)
treeedb6a8a8fa38f798a60db7913c3518db9630e6ef
parent740b8e8cce9b7523d4093b7692b079425eb08596 (diff)
downloadmutter-b891f8a52c54280cbaed1d163eac154b67a3a2be.tar.gz
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: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2175>
-rw-r--r--src/compositor/meta-window-actor-x11.c282
-rw-r--r--src/x11/meta-sync-counter.c265
-rw-r--r--src/x11/meta-sync-counter.h20
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;
-
- 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;
- }
+ MetaWindow *window =
+ meta_window_actor_get_meta_window (META_WINDOW_ACTOR (actor_x11));
+ MetaSyncCounter *sync_counter;
- 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 */