[gtk+/xpresent] gdkwindow-x11: Implement support for the X Present extension



commit 6d8a6634cf8c82b75fb84d25c794021e6f505e59
Author: Jasper St. Pierre <jstpierre mecheye net>
Date:   Thu Nov 20 17:29:54 2014 -0800

    gdkwindow-x11: Implement support for the X Present extension
    
    This allows us better synchronization than simply using XCopyArea, which
    is what cairo does by default.

 configure.ac             |   16 ++++++++++++
 gdk/gdkwindow.c          |    3 +-
 gdk/gdkwindowimpl.h      |    1 +
 gdk/x11/gdkdisplay-x11.c |   16 ++++++++++++
 gdk/x11/gdkdisplay-x11.h |    2 +
 gdk/x11/gdkwindow-x11.c  |   58 +++++++++++++++++++++++++++++++++++++++++++++-
 6 files changed, 93 insertions(+), 3 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 666bae1..e0be901 100644
--- a/configure.ac
+++ b/configure.ac
@@ -310,6 +310,10 @@ AC_ARG_ENABLE(xdamage,
               [AS_HELP_STRING([--enable-xdamage],
                               [support X Damage extension [default=maybe]])],,
               [enable_xdamage="maybe"])
+AC_ARG_ENABLE(xpresent,
+              [AS_HELP_STRING([--enable-xpresent],
+                              [support X Present extension [default=maybe]])],,
+              [enable_xpresent="maybe"])
 
 AC_ARG_ENABLE(x11-backend,
               [AS_HELP_STRING([--enable-x11-backend],
@@ -1286,6 +1290,18 @@ if test "x$enable_x11_backend" = xyes; then
     fi
   fi
 
+  if test x"$enable_xpresent" != xno; then
+    if $PKG_CONFIG --exists xcb-present ; then
+      AC_DEFINE(HAVE_PRESENT, 1, [Have the Present X extension])
+
+      X_PACKAGES="$X_PACKAGES xcb-present"
+      X_EXTENSIONS="$X_EXTENSIONS Present"
+      GTK_PACKAGES_FOR_X="$GTK_PACKAGES_FOR_X xcb-present"
+    elif test x"$enable_xpresent" = xyes; then
+      AC_MSG_ERROR([Present support requested but xcb-present not found])
+    fi
+  fi
+
   if $have_base_x_pc ; then
     GDK_EXTRA_LIBS="$x_extra_libs"
   else
diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c
index 6d56a6c..2c6517e 100644
--- a/gdk/gdkwindow.c
+++ b/gdk/gdkwindow.c
@@ -3069,7 +3069,6 @@ gdk_window_end_paint (GdkWindow *window)
   if (impl_class->end_paint)
     impl_class->end_paint (window);
 
-
   if (window->current_paint.surface_needs_composite)
     {
       cairo_surface_t *surface;
@@ -3101,7 +3100,7 @@ gdk_window_end_paint (GdkWindow *window)
                                     window->current_paint.region,
                                     window->active_update_area);
         }
-      else
+      else if (!impl_class->do_composite (window))
         {
           surface = gdk_window_ref_impl_surface (window);
           cr = cairo_create (surface);
diff --git a/gdk/gdkwindowimpl.h b/gdk/gdkwindowimpl.h
index b8fb0f0..b442325 100644
--- a/gdk/gdkwindowimpl.h
+++ b/gdk/gdkwindowimpl.h
@@ -299,6 +299,7 @@ struct _GdkWindowImplClass
                                            GError        **error);
   void         (*invalidate_for_new_frame)(GdkWindow      *window,
                                            cairo_region_t *update_area);
+  gboolean     (*do_composite)            (GdkWindow      *window);
 };
 
 /* Interface Functions */
diff --git a/gdk/x11/gdkdisplay-x11.c b/gdk/x11/gdkdisplay-x11.c
index d6543c1..44e9c71 100644
--- a/gdk/x11/gdkdisplay-x11.c
+++ b/gdk/x11/gdkdisplay-x11.c
@@ -49,6 +49,7 @@
 
 #include <X11/Xatom.h>
 #include <X11/Xlibint.h>
+#include <X11/Xlib-xcb.h>
 
 #ifdef HAVE_XKB
 #include <X11/XKBlib.h>
@@ -72,6 +73,10 @@
 #include <X11/extensions/Xrandr.h>
 #endif
 
+#ifdef HAVE_PRESENT
+#include <xcb/present.h>
+#endif
+
 typedef struct _GdkErrorTrap  GdkErrorTrap;
 
 struct _GdkErrorTrap
@@ -1366,6 +1371,7 @@ _gdk_x11_display_open (const gchar *display_name)
   GdkWindowAttr attr;
   gint argc;
   gchar *argv[1];
+  xcb_connection_t *xcb_conn;
 
   XClassHint *class_hint;
   gulong pid;
@@ -1386,6 +1392,8 @@ _gdk_x11_display_open (const gchar *display_name)
 
   _gdk_x11_precache_atoms (display, precache_atoms, G_N_ELEMENTS (precache_atoms));
 
+  xcb_conn = XGetXCBConnection (display_x11->xdisplay);
+
   /* RandR must be initialized before we initialize the screens */
   display_x11->have_randr12 = FALSE;
   display_x11->have_randr13 = FALSE;
@@ -1450,6 +1458,14 @@ _gdk_x11_display_open (const gchar *display_name)
 #endif
     display_x11->have_xfixes = FALSE;
 
+#ifdef HAVE_PRESENT
+  if (xcb_get_extension_data (xcb_conn, &xcb_present_id))
+    {
+      (void) xcb_present_query_version (xcb_conn, XCB_PRESENT_MAJOR_VERSION, XCB_PRESENT_MINOR_VERSION);
+      display_x11->have_present = TRUE;
+    }
+#endif
+
 #ifdef HAVE_XCOMPOSITE
   if (XCompositeQueryExtension (display_x11->xdisplay,
                                &ignore, &ignore))
diff --git a/gdk/x11/gdkdisplay-x11.h b/gdk/x11/gdkdisplay-x11.h
index f601ed3..a7fd8f2 100644
--- a/gdk/x11/gdkdisplay-x11.h
+++ b/gdk/x11/gdkdisplay-x11.h
@@ -68,6 +68,8 @@ struct _GdkX11Display
   gboolean have_randr13;
   gint xrandr_event_base;
 
+  gboolean have_present;
+
   /* If the SECURITY extension is in place, whether this client holds
    * a trusted authorization and so is allowed to make various requests
    * (grabs, properties etc.) Otherwise always TRUE.
diff --git a/gdk/x11/gdkwindow-x11.c b/gdk/x11/gdkwindow-x11.c
index a7be5de..369a96a 100644
--- a/gdk/x11/gdkwindow-x11.c
+++ b/gdk/x11/gdkwindow-x11.c
@@ -53,6 +53,7 @@
 #include <X11/Xlib.h>
 #include <X11/Xutil.h>
 #include <X11/Xatom.h>
+#include <X11/Xlib-xcb.h>
 
 #include <X11/extensions/shape.h>
 
@@ -72,6 +73,10 @@
 #include <X11/extensions/Xdamage.h>
 #endif
 
+#ifdef HAVE_PRESENT
+#include <xcb/present.h>
+#endif
+
 const int _gdk_x11_event_mask_table[21] =
 {
   ExposureMask,
@@ -3398,7 +3403,7 @@ do_shape_combine_region (GdkWindow       *window,
       _gdk_x11_region_get_xrectangles (shape_region,
                                        0, 0, impl->window_scale,
                                        &xrects, &n_rects);
-      
+
       if (shape == ShapeBounding)
        {
          _gdk_x11_window_tmp_unset_parent_bg (window);
@@ -5683,6 +5688,56 @@ gdk_x11_window_show_window_menu (GdkWindow *window,
   return TRUE;
 }
 
+static gboolean
+gdk_x11_window_do_composite (GdkWindow *window)
+{
+  GdkDisplay *display = gdk_window_get_display (window);
+  GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
+
+#ifdef HAVE_PRESENT
+  if (display_x11->have_present)
+    {
+      Display *xdisplay = GDK_DISPLAY_XDISPLAY (display);
+      xcb_connection_t *xcb_conn = XGetXCBConnection (xdisplay);
+      XserverRegion update_region;
+      XRectangle *rects;
+      int n_rects;
+      double sx, sy;
+      double offs_x, offs_y;
+
+      cairo_surface_get_device_scale (window->current_paint.surface, &sx, &sy);
+      cairo_surface_get_device_offset (window->current_paint.surface, &offs_x, &offs_y);
+
+      _gdk_x11_region_get_xrectangles (window->current_paint.region,
+                                       offs_x / sx, offs_y / sy, sx, &rects, &n_rects);
+      update_region = XFixesCreateRegion (xdisplay, rects, n_rects);
+
+      xcb_present_pixmap (xcb_conn,
+                          GDK_WINDOW_XID (window),
+                          cairo_xlib_surface_get_drawable (window->current_paint.surface),
+                          XNextRequest (xdisplay),
+                          update_region,
+                          update_region,
+                          -offs_x,
+                          -offs_y,
+                          None, /* target_crtc */
+                          None, /* wait_fence */
+                          None, /* idle_fence */
+                          0, /* options */
+                          0, /* target_msc */
+                          0, /* divisor */
+                          0, /* remainder */
+                          0, NULL /* notifies */ );
+
+      XFixesDestroyRegion (xdisplay, update_region);
+
+      return TRUE;
+    }
+#endif
+
+  return FALSE;
+}
+
 static void
 gdk_window_impl_x11_class_init (GdkWindowImplX11Class *klass)
 {
@@ -5773,4 +5828,5 @@ gdk_window_impl_x11_class_init (GdkWindowImplX11Class *klass)
   impl_class->create_gl_context = gdk_x11_window_create_gl_context;
   impl_class->invalidate_for_new_frame = gdk_x11_window_invalidate_for_new_frame;
   impl_class->get_unscaled_size = gdk_x11_window_get_unscaled_size;
+  impl_class->do_composite = gdk_x11_window_do_composite;
 }


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