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>
This commit is contained in:
Carlos Garnacho 2022-09-15 00:30:23 +02:00 committed by Marge Bot
parent 740b8e8cce
commit b891f8a52c
3 changed files with 312 additions and 255 deletions

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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 */