[mutter/gnome-3-14] Fix problems resulting in left-over queued frames
- From: Owen Taylor <otaylor src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [mutter/gnome-3-14] Fix problems resulting in left-over queued frames
- Date: Tue, 2 Dec 2014 16:49:57 +0000 (UTC)
commit 7d3204b1965fd54f28f73013f4700caf37dd8216
Author: Owen W. Taylor <otaylor fishsoup net>
Date: Fri Oct 17 08:49:54 2014 -0400
Fix problems resulting in left-over queued frames
* Use -1 rather than 0 as a flag for pending queue entries; 0 is
a valid frame_counter value from Cogl.
* Consistently handle the fact we can have more than one pending
entry. It's app misbehavior to submit a new frame before
_NET_WM_FRAME_DRAWN is received; but we accept such frame messages,
so we can't just leak them.
* If we remove send_frame_message_timer, assign the current frame counter
to pending entries.
* To try to avoid regressing on this, when sending _NET_WM_FRAME_TIMINGS
messages, if we have stale messages, or messages with no frame drawn
time, warn and remove them from the queue rather than just accumulating.
* Improve commenting.
https://bugzilla.gnome.org/show_bug.cgi?id=738686
src/compositor/meta-window-actor.c | 121 +++++++++++++++++++++++++-----------
1 files changed, 85 insertions(+), 36 deletions(-)
---
diff --git a/src/compositor/meta-window-actor.c b/src/compositor/meta-window-actor.c
index eb21c46..254a1a9 100644
--- a/src/compositor/meta-window-actor.c
+++ b/src/compositor/meta-window-actor.c
@@ -100,7 +100,7 @@ struct _MetaWindowActorPrivate
guint disposed : 1;
/* If set, the client needs to be sent a _NET_WM_FRAME_DRAWN
- * client message using the most recent frame in ->frames */
+ * client message for one or more messages in ->frames */
guint needs_frame_drawn : 1;
guint repaint_scheduled : 1;
@@ -118,10 +118,21 @@ struct _MetaWindowActorPrivate
typedef struct _FrameData FrameData;
+/* 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.
+ */
struct _FrameData
{
- int64_t frame_counter;
guint64 sync_request_serial;
+ int64_t frame_counter;
gint64 frame_drawn_time;
};
@@ -656,6 +667,30 @@ clip_shadow_under_window (MetaWindowActor *self)
}
static void
+assign_frame_counter_to_frames (MetaWindowActor *self)
+{
+ MetaWindowActorPrivate *priv = self->priv;
+ GList *l;
+
+ /* If the window is obscured, then we're expecting to deal with sending
+ * frame messages in a timeout, rather than in this paint cycle.
+ */
+ if (priv->send_frame_messages_timer != 0)
+ return;
+
+ for (l = priv->frames; l; l = l->next)
+ {
+ FrameData *frame = l->data;
+
+ if (frame->frame_counter == -1)
+ {
+ CoglOnscreen *onscreen = COGL_ONSCREEN (cogl_get_draw_framebuffer());
+ frame->frame_counter = cogl_onscreen_get_frame_counter (onscreen);
+ }
+ }
+}
+
+static void
meta_window_actor_paint (ClutterActor *actor)
{
MetaWindowActor *self = META_WINDOW_ACTOR (actor);
@@ -671,6 +706,8 @@ meta_window_actor_paint (ClutterActor *actor)
{
g_source_remove (priv->send_frame_messages_timer);
priv->send_frame_messages_timer = 0;
+
+ assign_frame_counter_to_frames (self);
}
if (shadow != NULL)
@@ -873,16 +910,27 @@ send_frame_messages_timeout (gpointer data)
{
MetaWindowActor *self = (MetaWindowActor *) data;
MetaWindowActorPrivate *priv = self->priv;
- FrameData *frame = g_slice_new0 (FrameData);
+ GList *l;
- frame->sync_request_serial = priv->window->sync_request_serial;
+ for (l = priv->frames; l;)
+ {
+ GList *l_next = l->next;
+ FrameData *frame = l->data;
- do_send_frame_drawn (self, frame);
- do_send_frame_timings (self, frame, 0, 0);
+ if (frame->frame_counter == -1)
+ {
+ do_send_frame_drawn (self, frame);
+ do_send_frame_timings (self, frame, 0, 0);
+
+ priv->frames = g_list_delete_link (priv->frames, l);
+ frame_data_free (frame);
+ }
+
+ l = l_next;
+ }
priv->needs_frame_drawn = FALSE;
priv->send_frame_messages_timer = 0;
- frame_data_free (frame);
return FALSE;
}
@@ -933,6 +981,7 @@ meta_window_actor_queue_frame_drawn (MetaWindowActor *self,
return;
frame = g_slice_new0 (FrameData);
+ frame->frame_counter = -1;
priv->needs_frame_drawn = TRUE;
@@ -1905,24 +1954,12 @@ meta_window_actor_handle_updates (MetaWindowActor *self)
void
meta_window_actor_pre_paint (MetaWindowActor *self)
{
- MetaWindowActorPrivate *priv = self->priv;
- GList *l;
-
if (meta_window_actor_is_destroyed (self))
return;
meta_window_actor_handle_updates (self);
- for (l = priv->frames; l != NULL; l = l->next)
- {
- FrameData *frame = l->data;
-
- if (frame->frame_counter == 0)
- {
- CoglOnscreen *onscreen = COGL_ONSCREEN (cogl_get_draw_framebuffer());
- frame->frame_counter = cogl_onscreen_get_frame_counter (onscreen);
- }
- }
+ assign_frame_counter_to_frames (self);
}
static void
@@ -1963,16 +2000,23 @@ meta_window_actor_post_paint (MetaWindowActor *self)
if (meta_window_actor_is_destroyed (self))
return;
- /* This window had damage, but wasn't actually redrawn because
- * it is obscured. So we should wait until timer expiration
- * before sending _NET_WM_FRAME_* messages.
- */
- if (priv->send_frame_messages_timer != 0)
- return;
-
- if (priv->needs_frame_drawn)
+ /* 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 (priv->send_frame_messages_timer == 0 &&
+ priv->needs_frame_drawn)
{
- do_send_frame_drawn (self, priv->frames->data);
+ GList *l;
+
+ for (l = priv->frames; l; l = l->next)
+ {
+ FrameData *frame = l->data;
+
+ if (frame->frame_drawn_time == 0)
+ do_send_frame_drawn (self, frame);
+ }
+
priv->needs_frame_drawn = FALSE;
}
@@ -2057,15 +2101,20 @@ meta_window_actor_frame_complete (MetaWindowActor *self,
{
GList *l_next = l->next;
FrameData *frame = l->data;
+ gint64 frame_counter = cogl_frame_info_get_frame_counter (frame_info);
- if (frame->frame_counter == cogl_frame_info_get_frame_counter (frame_info))
+ if (frame->frame_counter != -1 && frame->frame_counter <= frame_counter)
{
- if (frame->frame_drawn_time != 0)
- {
- priv->frames = g_list_delete_link (priv->frames, l);
- send_frame_timings (self, frame, frame_info, presentation_time);
- frame_data_free (frame);
- }
+ if (G_UNLIKELY (frame->frame_drawn_time == 0))
+ g_warning ("%s: Frame has assigned frame counter but no frame drawn time",
+ priv->window->desc);
+ if (G_UNLIKELY (frame->frame_counter < frame_counter))
+ g_warning ("%s: frame_complete callback never occurred for frame %" G_GINT64_FORMAT,
+ priv->window->desc, frame->frame_counter);
+
+ priv->frames = g_list_delete_link (priv->frames, l);
+ send_frame_timings (self, frame, frame_info, presentation_time);
+ frame_data_free (frame);
}
l = l_next;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]