]> Pileus Git - ~andy/gtk/commitdiff
Add GdkFrameHistory and GdkFrameTimings, handle _NET_WM_FRAME_TIMINGS
authorOwen W. Taylor <otaylor@fishsoup.net>
Wed, 14 Nov 2012 17:49:06 +0000 (12:49 -0500)
committerOwen W. Taylor <otaylor@fishsoup.net>
Thu, 14 Feb 2013 22:19:50 +0000 (17:19 -0500)
In order to be able to track statistics about how well we are drawing,
and in order to be able to do sophisticated things with frame timing
like predicting per-frame latencies and synchronizing audio with video,
we need to be able to track exactly when previous frames were drawn
to the screen.

Information about each frame is stored in a new GdkFrameTimings object.
A new GdkFrameHistory object is added which keeps a queue of recent
GdkFrameTimings (this is added to avoid further complicating the
implementation of GdkFrameClock.)

https://bugzilla.gnome.org/show_bug.cgi?id=685460

gdk/Makefile.am
gdk/gdkframeclock.c
gdk/gdkframeclock.h
gdk/gdkframeclockidle.c
gdk/gdkframehistory.c [new file with mode: 0644]
gdk/gdkframehistory.h [new file with mode: 0644]
gdk/gdkframetimings.c [new file with mode: 0644]
gdk/gdkframetimings.h [new file with mode: 0644]
gdk/x11/gdkdisplay-x11.c
gdk/x11/gdkwindow-x11.c

index a265bcaf178497ea05a5685cc74fa68dd80ffef2..61aeb4bc7fe352d5d5e9470d54fa9f999864fbab 100644 (file)
@@ -75,6 +75,8 @@ gdk_public_h_sources =                                \
        gdkdisplaymanager.h                     \
        gdkdnd.h                                \
        gdkevents.h                             \
+       gdkframehistory.h                       \
+       gdkframetimings.h                       \
        gdkkeys.h                               \
        gdkkeysyms.h                            \
        gdkkeysyms-compat.h                     \
@@ -123,6 +125,8 @@ gdk_c_sources =                             \
        gdkdisplaymanager.c                     \
        gdkdnd.c                                \
        gdkevents.c                             \
+       gdkframehistory.c                       \
+       gdkframetimings.c                       \
        gdkglobals.c                            \
        gdkkeys.c                               \
        gdkkeyuni.c                             \
index 8c6d202102b1fae171b08d5f06f3755320568f0a..ecb84bd8aa338ac3c8b1dd0b2d8caff1d4d33986 100644 (file)
@@ -304,6 +304,23 @@ gdk_frame_clock_thaw (GdkFrameClock *clock)
   GDK_FRAME_CLOCK_GET_IFACE (clock)->thaw (clock);
 }
 
+/**
+ * gdk_frame_clock_get_history:
+ * @clock: the clock
+ *
+ * Gets the #GdkFrameHistory for the frame clock.
+ *
+ * Since: 3.8
+ * Return value: (transfer none): the frame history object
+ */
+GdkFrameHistory *
+gdk_frame_clock_get_history (GdkFrameClock *clock)
+{
+  g_return_val_if_fail (GDK_IS_FRAME_CLOCK (clock), NULL);
+
+  return GDK_FRAME_CLOCK_GET_IFACE (clock)->get_history (clock);
+}
+
 /**
  * gdk_frame_clock_get_requested:
  * @clock: the clock
index d75fce984a2c43ffc07c8ded9d5d44d5c50a12a4..03b04304cd0fb6efc9630e978bf9152186105bc8 100644 (file)
@@ -31,7 +31,7 @@
 #ifndef __GDK_FRAME_CLOCK_H__
 #define __GDK_FRAME_CLOCK_H__
 
-#include <glib-object.h>
+#include <gdk/gdkframehistory.h>
 
 G_BEGIN_DECLS
 
@@ -87,6 +87,8 @@ struct _GdkFrameClockInterface
   void     (* freeze)              (GdkFrameClock *clock);
   void     (* thaw)                (GdkFrameClock *clock);
 
+  GdkFrameHistory *  (* get_history)   (GdkFrameClock *clock);
+
   /* signals */
   /* void (* frame_requested)    (GdkFrameClock *clock); */
   /* void (* flush_events)       (GdkFrameClock *clock); */
@@ -109,6 +111,8 @@ GdkFrameClockPhase gdk_frame_clock_get_requested (GdkFrameClock      *clock);
 void     gdk_frame_clock_freeze              (GdkFrameClock *clock);
 void     gdk_frame_clock_thaw                (GdkFrameClock *clock);
 
+GdkFrameHistory *gdk_frame_clock_get_history (GdkFrameClock *clock);
+
 /* Convenience API */
 void  gdk_frame_clock_get_frame_time_val (GdkFrameClock  *clock,
                                           GTimeVal       *timeval);
index c8a90368ac6e222b0a0ce3e1bd10dd79b6c16c18..00d284c039614bedcd2d8540cb871117e141069a 100644 (file)
@@ -33,6 +33,7 @@
 
 struct _GdkFrameClockIdlePrivate
 {
+  GdkFrameHistory *history;
   GTimer *timer;
   /* timer_base is used to avoid ever going backward */
   guint64 timer_base;
@@ -77,6 +78,7 @@ gdk_frame_clock_idle_init (GdkFrameClockIdle *frame_clock_idle)
                                                         GdkFrameClockIdlePrivate);
   priv = frame_clock_idle->priv;
 
+  priv->history = gdk_frame_history_new ();
   priv->timer = g_timer_new ();
   priv->freeze_count = 0;
 }
@@ -229,7 +231,14 @@ gdk_frame_clock_paint_idle (void *data)
         case GDK_FRAME_CLOCK_PHASE_BEFORE_PAINT:
           if (priv->freeze_count == 0)
             {
+              GdkFrameTimings *timings;
+              gint64 frame_counter;
+
               priv->frame_time = compute_frame_time (clock_idle);
+              gdk_frame_history_begin_frame (priv->history);
+              frame_counter = gdk_frame_history_get_frame_counter (priv->history);
+              timings = gdk_frame_history_get_timings (priv->history, frame_counter);
+              gdk_frame_timings_set_frame_time (timings, priv->frame_time);
 
               priv->phase = GDK_FRAME_CLOCK_PHASE_BEFORE_PAINT;
 
@@ -370,6 +379,15 @@ gdk_frame_clock_idle_thaw (GdkFrameClock *clock)
     }
 }
 
+static GdkFrameHistory *
+gdk_frame_clock_idle_get_history (GdkFrameClock *clock)
+{
+  GdkFrameClockIdle *clock_idle = GDK_FRAME_CLOCK_IDLE (clock);
+  GdkFrameClockIdlePrivate *priv = clock_idle->priv;
+
+  return priv->history;
+}
+
 static void
 gdk_frame_clock_idle_interface_init (GdkFrameClockInterface *iface)
 {
@@ -378,6 +396,7 @@ gdk_frame_clock_idle_interface_init (GdkFrameClockInterface *iface)
   iface->get_requested = gdk_frame_clock_idle_get_requested;
   iface->freeze = gdk_frame_clock_idle_freeze;
   iface->thaw = gdk_frame_clock_idle_thaw;
+  iface->get_history = gdk_frame_clock_idle_get_history;
 }
 
 GdkFrameClock *
diff --git a/gdk/gdkframehistory.c b/gdk/gdkframehistory.c
new file mode 100644 (file)
index 0000000..e993e5e
--- /dev/null
@@ -0,0 +1,143 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 2012 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include "gdkframehistory.h"
+
+#define FRAME_HISTORY_MAX_LENGTH 16
+
+struct _GdkFrameHistory
+{
+  GObject parent_instance;
+
+  gint64 frame_counter;
+  gint n_timings;
+  gint current;
+  GdkFrameTimings *timings[FRAME_HISTORY_MAX_LENGTH];
+};
+
+struct _GdkFrameHistoryClass
+{
+  GObjectClass parent_class;
+};
+
+G_DEFINE_TYPE (GdkFrameHistory, gdk_frame_history, G_TYPE_OBJECT)
+
+static void
+gdk_frame_history_finalize (GObject *object)
+{
+  GdkFrameHistory *history = GDK_FRAME_HISTORY (object);
+  int i;
+
+  for (i = 0; i < FRAME_HISTORY_MAX_LENGTH; i++)
+    if (history->timings[i] != 0)
+      gdk_frame_timings_unref (history->timings[i]);
+
+  G_OBJECT_CLASS (gdk_frame_history_parent_class)->finalize (object);
+}
+
+static void
+gdk_frame_history_class_init (GdkFrameHistoryClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->finalize = gdk_frame_history_finalize;
+}
+
+static void
+gdk_frame_history_init (GdkFrameHistory *history)
+{
+  history->frame_counter = -1;
+  history->current = FRAME_HISTORY_MAX_LENGTH - 1;
+}
+
+GdkFrameHistory *
+gdk_frame_history_new (void)
+{
+  return g_object_new (GDK_TYPE_FRAME_HISTORY, NULL);
+}
+
+gint64
+gdk_frame_history_get_frame_counter (GdkFrameHistory *history)
+{
+  g_return_val_if_fail (GDK_IS_FRAME_HISTORY (history), 0);
+
+  return history->frame_counter;
+}
+
+gint64
+gdk_frame_history_get_start (GdkFrameHistory *history)
+{
+  g_return_val_if_fail (GDK_IS_FRAME_HISTORY (history), 0);
+
+  return history->frame_counter + 1 - history->n_timings;
+}
+
+void
+gdk_frame_history_begin_frame (GdkFrameHistory *history)
+{
+  g_return_if_fail (GDK_IS_FRAME_HISTORY (history));
+
+  history->frame_counter++;
+  history->current = (history->current + 1) % FRAME_HISTORY_MAX_LENGTH;
+
+  if (history->n_timings < FRAME_HISTORY_MAX_LENGTH)
+    history->n_timings++;
+  else
+    {
+      gdk_frame_timings_unref(history->timings[history->current]);
+    }
+
+  history->timings[history->current] = gdk_frame_timings_new (history->frame_counter);
+}
+
+GdkFrameTimings *
+gdk_frame_history_get_timings (GdkFrameHistory *history,
+                               gint64           frame_counter)
+{
+  gint pos;
+
+  g_return_val_if_fail (GDK_IS_FRAME_HISTORY (history), NULL);
+
+  if (frame_counter > history->frame_counter)
+    return NULL;
+
+  if (frame_counter <= history->frame_counter - history->n_timings)
+    return NULL;
+
+  pos = (history->current - (history->frame_counter - frame_counter) + FRAME_HISTORY_MAX_LENGTH) % FRAME_HISTORY_MAX_LENGTH;
+
+  return history->timings[pos];
+}
+
+GdkFrameTimings *
+gdk_frame_history_get_last_complete (GdkFrameHistory *history)
+{
+  gint i;
+
+  g_return_val_if_fail (GDK_IS_FRAME_HISTORY (history), NULL);
+
+  for (i = 0; i < history->n_timings; i++)
+    {
+      gint pos = ((history->current - i) + FRAME_HISTORY_MAX_LENGTH) % FRAME_HISTORY_MAX_LENGTH;
+      if (gdk_frame_timings_get_complete (history->timings[pos]))
+        return history->timings[pos];
+    }
+
+  return NULL;
+}
diff --git a/gdk/gdkframehistory.h b/gdk/gdkframehistory.h
new file mode 100644 (file)
index 0000000..56e9db9
--- /dev/null
@@ -0,0 +1,49 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 2012 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#if !defined (__GDK_H_INSIDE__) && !defined (GDK_COMPILATION)
+#error "Only <gdk/gdk.h> can be included directly."
+#endif
+
+#ifndef __GDK_FRAME_HISTORY_H__
+#define __GDK_FRAME_HISTORY_H__
+
+#include <gdk/gdkframetimings.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GdkFrameHistory      GdkFrameHistory;
+typedef struct _GdkFrameHistoryClass GdkFrameHistoryClass;
+
+#define GDK_TYPE_FRAME_HISTORY  (gdk_frame_history_get_type ())
+#define GDK_FRAME_HISTORY(o)    (G_TYPE_CHECK_INSTANCE_CAST ((o), GDK_TYPE_FRAME_HISTORY, GdkFrameHistory))
+#define GDK_IS_FRAME_HISTORY(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDK_TYPE_FRAME_HISTORY))
+
+GType            gdk_frame_history_get_type (void) G_GNUC_CONST;
+
+GdkFrameHistory *gdk_frame_history_new (void);
+
+gint64           gdk_frame_history_get_frame_counter (GdkFrameHistory *history);
+gint64           gdk_frame_history_get_start         (GdkFrameHistory *history);
+void             gdk_frame_history_begin_frame       (GdkFrameHistory *history);
+GdkFrameTimings *gdk_frame_history_get_timings       (GdkFrameHistory *history,
+                                                      gint64           frame_counter);
+GdkFrameTimings *gdk_frame_history_get_last_complete (GdkFrameHistory *history);
+
+G_END_DECLS
+
+#endif /* __GDK_FRAME_HISTORY_H__ */
diff --git a/gdk/gdkframetimings.c b/gdk/gdkframetimings.c
new file mode 100644 (file)
index 0000000..d9354ed
--- /dev/null
@@ -0,0 +1,180 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 2012 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include "gdkframetimings.h"
+
+struct _GdkFrameTimings
+{
+  guint ref_count;
+
+  gboolean complete;
+  gint64 frame_counter;
+  guint64 cookie;
+  gint64 frame_time;
+  gint64 drawn_time;
+  gint64 presentation_time;
+  gint64 refresh_interval;
+};
+
+G_DEFINE_BOXED_TYPE (GdkFrameTimings, gdk_frame_timings,
+                     gdk_frame_timings_ref,
+                     gdk_frame_timings_unref)
+
+GdkFrameTimings *
+gdk_frame_timings_new (gint64 frame_counter)
+{
+  GdkFrameTimings *timings;
+
+  timings = g_slice_new0 (GdkFrameTimings);
+  timings->ref_count = 1;
+  timings->frame_counter = frame_counter;
+
+  return timings;
+}
+
+GdkFrameTimings *
+gdk_frame_timings_ref (GdkFrameTimings *timings)
+{
+  g_return_val_if_fail (timings != NULL, NULL);
+
+  timings->ref_count++;
+
+  return timings;
+}
+
+void
+gdk_frame_timings_unref (GdkFrameTimings *timings)
+{
+  g_return_if_fail (timings != NULL);
+  g_return_if_fail (timings->ref_count > 0);
+
+  timings->ref_count--;
+  if (timings->ref_count == 0)
+    {
+      g_slice_free (GdkFrameTimings, timings);
+    }
+}
+
+gint64
+gdk_frame_timings_get_frame_counter (GdkFrameTimings *timings)
+{
+  return timings->frame_counter;
+}
+
+guint64
+gdk_frame_timings_get_cookie (GdkFrameTimings *timings)
+{
+  g_return_val_if_fail (timings != NULL, 0);
+
+  return timings->cookie;
+}
+
+void
+gdk_frame_timings_set_cookie (GdkFrameTimings *timings,
+                              guint64          cookie)
+{
+  g_return_if_fail (timings != NULL);
+
+  timings->cookie = cookie;
+}
+
+gboolean
+gdk_frame_timings_get_complete (GdkFrameTimings *timings)
+{
+  g_return_val_if_fail (timings != NULL, FALSE);
+
+  return timings->complete;
+}
+
+void
+gdk_frame_timings_set_complete (GdkFrameTimings *timings,
+                                gboolean         complete)
+{
+  g_return_if_fail (timings != NULL);
+
+  timings->complete = complete;
+}
+
+gint64
+gdk_frame_timings_get_frame_time (GdkFrameTimings *timings)
+{
+  g_return_val_if_fail (timings != NULL, 0);
+
+  return timings->frame_time;
+}
+
+void
+gdk_frame_timings_set_frame_time (GdkFrameTimings *timings,
+                                  gint64           frame_time)
+{
+  g_return_if_fail (timings != NULL);
+
+  timings->frame_time = frame_time;
+}
+
+gint64
+gdk_frame_timings_get_drawn_time (GdkFrameTimings *timings)
+{
+  g_return_val_if_fail (timings != NULL, 0);
+
+  return timings->drawn_time;
+}
+
+void
+gdk_frame_timings_set_drawn_time (GdkFrameTimings *timings,
+                                  gint64           drawn_time)
+{
+  g_return_if_fail (timings != NULL);
+
+  timings->drawn_time = drawn_time;
+}
+
+gint64
+gdk_frame_timings_get_presentation_time (GdkFrameTimings *timings)
+{
+  g_return_val_if_fail (timings != NULL, 0);
+
+  return timings->presentation_time;
+}
+
+void
+gdk_frame_timings_set_presentation_time (GdkFrameTimings *timings,
+                                         gint64           presentation_time)
+{
+  g_return_if_fail (timings != NULL);
+
+  timings->presentation_time = presentation_time;
+}
+
+gint64
+gdk_frame_timings_get_refresh_interval (GdkFrameTimings *timings)
+{
+  g_return_val_if_fail (timings != NULL, 0);
+
+  return timings->refresh_interval;
+}
+
+void
+gdk_frame_timings_set_refresh_interval (GdkFrameTimings *timings,
+                                        gint64           refresh_interval)
+{
+  g_return_if_fail (timings != NULL);
+
+  timings->refresh_interval = refresh_interval;
+}
diff --git a/gdk/gdkframetimings.h b/gdk/gdkframetimings.h
new file mode 100644 (file)
index 0000000..7fddbd4
--- /dev/null
@@ -0,0 +1,63 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 2012 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#if !defined (__GDK_H_INSIDE__) && !defined (GDK_COMPILATION)
+#error "Only <gdk/gdk.h> can be included directly."
+#endif
+
+#ifndef __GDK_FRAME_TIMINGS_H__
+#define __GDK_FRAME_TIMINGS_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GdkFrameTimings GdkFrameTimings;
+
+GType            gdk_frame_timings_get_type (void) G_GNUC_CONST;
+
+GdkFrameTimings *gdk_frame_timings_new (gint64 frame_counter);
+
+GdkFrameTimings *gdk_frame_timings_ref   (GdkFrameTimings *timings);
+void             gdk_frame_timings_unref (GdkFrameTimings *timings);
+
+gint64           gdk_frame_timings_get_frame_counter     (GdkFrameTimings *timings);
+
+guint64          gdk_frame_timings_get_cookie            (GdkFrameTimings *timings);
+void             gdk_frame_timings_set_cookie            (GdkFrameTimings *timings,
+                                                          guint64          cookie);
+
+gboolean         gdk_frame_timings_get_complete          (GdkFrameTimings *timings);
+void             gdk_frame_timings_set_complete          (GdkFrameTimings *timings,
+                                                          gboolean         complete);
+
+gint64           gdk_frame_timings_get_frame_time        (GdkFrameTimings *timings);
+void             gdk_frame_timings_set_frame_time        (GdkFrameTimings *timings,
+                                                          gint64           frame_time);
+gint64           gdk_frame_timings_get_drawn_time        (GdkFrameTimings *timings);
+void             gdk_frame_timings_set_drawn_time        (GdkFrameTimings *timings,
+                                                          gint64           frame_time);
+gint64           gdk_frame_timings_get_presentation_time (GdkFrameTimings *timings);
+void             gdk_frame_timings_set_presentation_time (GdkFrameTimings *timings,
+                                                          gint64           presentation_time);
+gint64           gdk_frame_timings_get_refresh_interval  (GdkFrameTimings *timings);
+void             gdk_frame_timings_set_refresh_interval  (GdkFrameTimings *timings,
+                                                          gint64           refresh_interval);
+
+G_END_DECLS
+
+#endif /* __GDK_FRAME_TIMINGS_H__ */
index 4e28f74ec054adaf8feb080d466a507eac5656d8..ae4aaafb0f5cc47c79b1f2b9e14052b42994ed06 100644 (file)
@@ -1056,6 +1056,26 @@ gdk_x11_display_translate_event (GdkEventTranslator *translator,
   return return_val;
 }
 
+static GdkFrameTimings *
+find_frame_timings (GdkFrameClock *clock,
+                    guint64        serial)
+{
+  GdkFrameHistory *history = gdk_frame_clock_get_history (clock);
+  gint64 start_frame, end_frame, i;
+
+  start_frame = gdk_frame_history_get_start (history);
+  end_frame = gdk_frame_history_get_frame_counter (history);
+  for (i = end_frame; i >= start_frame; i--)
+    {
+      GdkFrameTimings *timings = gdk_frame_history_get_timings (history, i);
+
+      if (gdk_frame_timings_get_cookie (timings) == serial)
+        return timings;
+    }
+
+  return NULL;
+}
+
 GdkFilterReturn
 _gdk_wm_protocols_filter (GdkXEvent *xev,
                          GdkEvent  *event,
@@ -1074,6 +1094,71 @@ _gdk_wm_protocols_filter (GdkXEvent *xev,
 
   display = GDK_WINDOW_DISPLAY (win);
 
+  /* This isn't actually WM_PROTOCOLS because that wouldn't leave enough space
+   * in the message for everything that gets stuffed in */
+  if (xevent->xclient.message_type == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_FRAME_DRAWN"))
+    {
+      GdkWindowImplX11 *window_impl;
+      window_impl = GDK_WINDOW_IMPL_X11 (event->any.window->impl);
+      if (window_impl->toplevel)
+        {
+          guint32 d0 = xevent->xclient.data.l[0];
+          guint32 d1 = xevent->xclient.data.l[1];
+          guint32 d2 = xevent->xclient.data.l[2];
+          guint32 d3 = xevent->xclient.data.l[3];
+
+          guint64 serial = ((guint64)d0 << 32) | d1;
+
+          GdkFrameClock *clock = gdk_window_get_frame_clock (event->any.window);
+          GdkFrameTimings *timings = find_frame_timings (clock, serial);
+
+          if (timings)
+            gdk_frame_timings_set_drawn_time (timings, ((guint64)d2 << 32) | d3);
+
+          if (window_impl->toplevel->frame_pending)
+            {
+              window_impl->toplevel->frame_pending = FALSE;
+              gdk_frame_clock_thaw (clock);
+            }
+        }
+
+      return GDK_FILTER_REMOVE;
+    }
+
+  if (xevent->xclient.message_type == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_FRAME_TIMINGS"))
+    {
+      GdkWindowImplX11 *window_impl;
+      window_impl = GDK_WINDOW_IMPL_X11 (event->any.window->impl);
+      if (window_impl->toplevel)
+        {
+          guint32 d0 = xevent->xclient.data.l[0];
+          guint32 d1 = xevent->xclient.data.l[1];
+          guint32 d2 = xevent->xclient.data.l[2];
+          guint32 d3 = xevent->xclient.data.l[3];
+
+          guint64 serial = ((guint64)d0 << 32) | d1;
+
+          GdkFrameClock *clock = gdk_window_get_frame_clock (event->any.window);
+          GdkFrameTimings *timings = find_frame_timings (clock, serial);
+
+          if (timings)
+            {
+              gint64 drawn_time = gdk_frame_timings_get_drawn_time (timings);
+              gint32 presentation_time_offset = (gint32)d2;
+              gint32 refresh_interval = d3;
+
+              if (drawn_time && presentation_time_offset)
+                gdk_frame_timings_set_presentation_time (timings,
+                                                         drawn_time + presentation_time_offset);
+
+              if (refresh_interval)
+                gdk_frame_timings_set_refresh_interval (timings, refresh_interval);
+
+              gdk_frame_timings_set_complete (timings, TRUE);
+            }
+        }
+    }
+
   if (xevent->xclient.message_type != gdk_x11_get_xatom_by_name_for_display (display, "WM_PROTOCOLS"))
     return GDK_FILTER_CONTINUE;
 
@@ -1145,21 +1230,6 @@ _gdk_wm_protocols_filter (GdkXEvent *xev,
       return GDK_FILTER_REMOVE;
     }
 
-  else if (atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_FRAME_DRAWN"))
-    {
-      GdkWindowImplX11 *window_impl;
-
-      window_impl = GDK_WINDOW_IMPL_X11 (event->any.window->impl);
-      if (window_impl->toplevel &&
-          window_impl->toplevel->frame_pending)
-        {
-          window_impl->toplevel->frame_pending = FALSE;
-          gdk_frame_clock_thaw (gdk_window_get_frame_clock (event->any.window));
-        }
-
-      return GDK_FILTER_REMOVE;
-    }
-
   return GDK_FILTER_CONTINUE;
 }
 
index f2c5735e79d5c8d26e6c7d4245c81547bbf2cf37..874db0a8076d5c0186181d59588398e5528594b7 100644 (file)
@@ -853,7 +853,17 @@ static void
 on_frame_clock_after_paint (GdkFrameClock *clock,
                             GdkWindow     *window)
 {
+  GdkToplevelX11 *toplevel = _gdk_x11_window_get_toplevel (window);
+  GdkFrameHistory *history = gdk_frame_clock_get_history (clock);
+  gint64 frame_counter = gdk_frame_history_get_frame_counter (history);
+  GdkFrameTimings *timings = gdk_frame_history_get_timings (history, frame_counter);
+
   gdk_x11_window_end_frame (window);
+
+  if (toplevel->frame_pending)
+    gdk_frame_timings_set_cookie (timings, toplevel->current_counter_value);
+  else
+    gdk_frame_timings_set_complete (timings, TRUE);
 }
 
 void