[gtk+] GdkWaylandWindow: synchronize frame drawing



commit ca120a98e56f66876f1958599388f1b6b64aa303
Author: Owen W. Taylor <otaylor fishsoup net>
Date:   Wed Apr 24 18:14:22 2013 -0400

    GdkWaylandWindow: synchronize frame drawing
    
    Use wl_surface_frame() to get notification when the compositor paints
    a frame, and use this to throttle drawing to the compositor's refresh
    cycle.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=698864

 gdk/wayland/gdkwindow-wayland.c |   73 +++++++++++++++++++++++++++++++++++++-
 1 files changed, 71 insertions(+), 2 deletions(-)
---
diff --git a/gdk/wayland/gdkwindow-wayland.c b/gdk/wayland/gdkwindow-wayland.c
index d9be90d..92a5988 100644
--- a/gdk/wayland/gdkwindow-wayland.c
+++ b/gdk/wayland/gdkwindow-wayland.c
@@ -26,6 +26,7 @@
 #include "gdkwindow.h"
 #include "gdkwindowimpl.h"
 #include "gdkdisplay-wayland.h"
+#include "gdkframeclockprivate.h"
 #include "gdkprivate-wayland.h"
 #include "gdkinternals.h"
 #include "gdkdeviceprivate.h"
@@ -140,6 +141,9 @@ struct _GdkWindowImplWayland
     } saved_fullscreen, saved_maximized;
 
   gboolean use_custom_surface;
+
+  gboolean pending_commit;
+  gint64 pending_frame_counter;
 };
 
 struct _GdkWindowImplWaylandClass
@@ -256,6 +260,63 @@ get_default_title (void)
   return title;
 }
 
+static void
+frame_callback (void               *data,
+                struct wl_callback *callback,
+                uint32_t            time)
+{
+  GdkWindow *window = data;
+  GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
+  GdkFrameClock *clock = gdk_window_get_frame_clock (window);
+  GdkFrameTimings *timings;
+
+  wl_callback_destroy (callback);
+  _gdk_frame_clock_thaw (clock);
+
+  timings = gdk_frame_clock_get_timings (clock, impl->pending_frame_counter);
+  impl->pending_frame_counter = 0;
+
+  if (timings == NULL)
+    return;
+
+  timings->complete = TRUE;
+
+#ifdef G_ENABLE_DEBUG
+  if ((_gdk_debug_flags & GDK_DEBUG_FRAMES) != 0)
+    _gdk_frame_clock_debug_print_timings (clock, timings);
+#endif
+}
+
+static const struct wl_callback_listener listener = {
+  frame_callback
+};
+
+static void
+on_frame_clock_before_paint (GdkFrameClock *clock,
+                             GdkWindow     *window)
+{
+}
+
+static void
+on_frame_clock_after_paint (GdkFrameClock *clock,
+                            GdkWindow     *window)
+{
+  GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
+  struct wl_callback *callback;
+
+  if (!impl->pending_commit)
+    return;
+
+  impl->pending_commit = FALSE;
+  impl->pending_frame_counter = gdk_frame_clock_get_frame_counter (clock);
+
+  callback = wl_surface_frame (impl->surface);
+  wl_callback_add_listener (callback, &listener, window);
+  _gdk_frame_clock_freeze (clock);
+
+  wl_surface_commit (impl->surface);
+}
+
 void
 _gdk_wayland_display_create_window_impl (GdkDisplay    *display,
                                         GdkWindow     *window,
@@ -266,6 +327,7 @@ _gdk_wayland_display_create_window_impl (GdkDisplay    *display,
                                         gint           attributes_mask)
 {
   GdkWindowImplWayland *impl;
+  GdkFrameClock *frame_clock;
   const char *title;
 
   impl = g_object_new (GDK_TYPE_WINDOW_IMPL_WAYLAND, NULL);
@@ -306,6 +368,13 @@ _gdk_wayland_display_create_window_impl (GdkDisplay    *display,
 
   if (attributes_mask & GDK_WA_TYPE_HINT)
     gdk_window_set_type_hint (window, attributes->type_hint);
+
+  frame_clock = gdk_window_get_frame_clock (window);
+
+  g_signal_connect (frame_clock, "before-paint",
+                    G_CALLBACK (on_frame_clock_before_paint), window);
+  g_signal_connect (frame_clock, "after-paint",
+                    G_CALLBACK (on_frame_clock_after_paint), window);
 }
 
 static const cairo_user_data_key_t gdk_wayland_cairo_key;
@@ -368,6 +437,7 @@ gdk_wayland_window_attach_image (GdkWindow *window)
 
   /* Attach this new buffer to the surface */
   wl_surface_attach (impl->surface, data->buffer, dx, dy);
+  impl->pending_commit = TRUE;
 }
 
 static void
@@ -1640,9 +1710,8 @@ gdk_wayland_window_process_updates_recurse (GdkWindow      *window,
       cairo_region_get_rectangle (region, i, &rect);
       wl_surface_damage (impl->surface,
                          rect.x, rect.y, rect.width, rect.height);
+      impl->pending_commit = TRUE;
     }
-
-  wl_surface_commit (impl->surface);
 }
 
 static void


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]