[Xfce4-commits] [xfce/xfwm4] 03/09: Implement vsync using OpenGL

noreply at xfce.org noreply at xfce.org
Fri Mar 27 22:39:09 CET 2015


This is an automated email from the git hooks/post-receive script.

olivier pushed a commit to branch master
in repository xfce/xfwm4.

commit 8fbff6ce0c097897a1f909dd02f72f4160f23d99
Author: Olivier Fourdan <fourdan at xfce.org>
Date:   Tue Mar 24 21:04:17 2015 +0100

    Implement vsync using OpenGL
    
    Bug: 11642
    
    Signed-off-by: Olivier Fourdan <fourdan at xfce.org>
---
 configure.ac.in                    |   10 +-
 settings-dialogs/tweaks-settings.c |    2 +-
 src/Makefile.am                    |    3 +-
 src/compositor.c                   |  357 +++++++++++++-----------------------
 src/screen.h                       |   25 +--
 5 files changed, 149 insertions(+), 248 deletions(-)

diff --git a/configure.ac.in b/configure.ac.in
index af7084b..6d72221 100644
--- a/configure.ac.in
+++ b/configure.ac.in
@@ -19,7 +19,7 @@ m4_define([xcomposite_minimum_version], [0.2])
 m4_define([wnck_minimum_version], [2.22])
 m4_define([startup_notification_minimum_version], [0.5])
 m4_define([intltool_minimum_version], [0.31])
-m4_define([libdrm_minimum_version], [2.4])
+m4_define([libepoxy_minimum_version], [1.0])
 
 dnl init autoconf
 AC_COPYRIGHT([Copyright (c) 2002-2014
@@ -99,10 +99,10 @@ XDT_CHECK_PACKAGE([DBUS_GLIB], [dbus-glib-1], [0.72])
 dnl
 dnl Sync to vblank support
 dnl
-XDT_CHECK_OPTIONAL_PACKAGE([LIBDRM],
-                       [libdrm], [libdrm_minimum_version],
-                       [libdrm],
-                       [userspace interface to the kernel DRM services], [yes])
+XDT_CHECK_OPTIONAL_PACKAGE([EPOXY],
+                       [epoxy], [libepoxy_minimum_version],
+                       [epoxy],
+                       [library for handling OpenGL function pointer management], [yes])
 
 dnl
 dnl Startup notification support
diff --git a/settings-dialogs/tweaks-settings.c b/settings-dialogs/tweaks-settings.c
index 8585c53..7c4f1f7 100644
--- a/settings-dialogs/tweaks-settings.c
+++ b/settings-dialogs/tweaks-settings.c
@@ -399,7 +399,7 @@ wm_tweaks_dialog_configure_widgets (GtkBuilder *builder)
                             "/general/unredirect_overlays",
                             G_TYPE_BOOLEAN,
                             (GObject *)unredirect_overlays_check, "active");
-#ifdef HAVE_LIBDRM
+#ifdef HAVE_EPOXY
     xfconf_g_property_bind (xfwm4_channel,
                             "/general/sync_to_vblank",
                             G_TYPE_BOOLEAN,
diff --git a/src/Makefile.am b/src/Makefile.am
index ee2fff6..03649ca 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -80,9 +80,9 @@ xfwm4_CFLAGS =								\
 	$(LIBXFCE4UI_CFLAGS)						\
 	$(LIBXFCE4KBD_PRIVATE_CFLAGS)					\
 	$(RENDER_CFLAGS)						\
-	$(LIBDRM_CFLAGS)						\
 	$(LIBSTARTUP_NOTIFICATION_CFLAGS)				\
 	$(COMPOSITOR_CFLAGS)						\
+	$(EPOXY_CFLAGS)							\
 	-DPACKAGE_LOCALE_DIR=\"$(localedir)\"				\
 	-DDATADIR=\"$(datadir)\"					\
 	-DHELPERDIR=\"$(HELPER_PATH_PREFIX)\"				\
@@ -102,6 +102,7 @@ xfwm4_LDADD =								\
 	$(RENDER_LIBS)							\
 	$(COMPOSITOR_LIBS)						\
 	$(RANDR_LIBS) 							\
+	$(EPOXY_LIBS)							\
 	$(MATH_LIBS)
 
 EXTRA_DIST = 								\
diff --git a/src/compositor.c b/src/compositor.c
index 56e41b3..306a9ef 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -37,15 +37,10 @@
 #include <string.h>
 #include <libxfce4util/libxfce4util.h>
 
-#ifdef HAVE_LIBDRM
-#include <stdint.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <drm.h>
-#ifdef HAVE_STROPTS_H
-#include <stropts.h>
-#endif
-#endif /* HAVE_LIBDRM */
+#ifdef HAVE_EPOXY
+#include <epoxy/gl.h>
+#include <epoxy/glx.h>
+#endif /* HAVE_EPOXY */
 
 #include "display.h"
 #include "screen.h"
@@ -97,15 +92,6 @@
 
 /* Set TIMEOUT_REPAINT to 0 to disable timeout repaint */
 #define TIMEOUT_REPAINT       10 /* msec */
-#define TIMEOUT_REPAINT_MIN    1
-#define TIMEOUT_REPAINT_MAX   20
-#define TIMEOUT_DRI           10 /* seconds */
-
-#ifdef __OpenBSD__
-#define DRM_CARD0             "/dev/drm0"
-#else
-#define DRM_CARD0             "/dev/dri/card0"
-#endif
 
 typedef struct _CWindow CWindow;
 struct _CWindow
@@ -1282,112 +1268,136 @@ paint_win (CWindow *cw, XserverRegion region, gboolean solid_part)
     }
 }
 
-#if HAVE_LIBDRM
-#if TIMEOUT_REPAINT
-
-static void
-open_dri (ScreenInfo *screen_info)
-{
-    screen_info->dri_fd = open (DRM_CARD0, O_RDWR);
-    if (screen_info->dri_fd == -1)
-    {
-        g_warning ("Error opening %s: %s", DRM_CARD0, g_strerror (errno));
-    }
-}
-
-static void
-close_dri (ScreenInfo *screen_info)
-{
-    if (screen_info->dri_fd != -1)
-    {
-        close (screen_info->dri_fd);
-        screen_info->dri_fd = -1;
-    }
-}
-
+#if HAVE_EPOXY
 static gboolean
-dri_enabled (ScreenInfo *screen_info)
+vblank_enabled (ScreenInfo *screen_info)
 {
-    return (screen_info->dri_fd != -1 && screen_info->params->sync_to_vblank);
+    return (screen_info->params->sync_to_vblank &&
+            (screen_info->has_glx_video_sync || screen_info->has_glx_sync_control));
 }
 
-static void
-wait_vblank (ScreenInfo *screen_info)
-{
-    int retval;
-    drm_wait_vblank_t vblank;
+static gboolean
+vblank_init(ScreenInfo *screen_info)
+{
+    static int visual_attribs[] = {
+        GLX_X_RENDERABLE,  True,
+        GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
+        None
+    };
+    int version;
+    int n_configs;
+    int i;
+    GLXFBConfig* configs, fb_config;
+    gboolean fb_match;
+    VisualID xvisual_id;
+
+    version = epoxy_glx_version (myScreenGetXDisplay (screen_info), screen_info->screen);
+    if (version < 13)
+    {
+        g_warning ("GLX version %d is too old, vsync disabled.");
+        return FALSE;
+    }
 
-    if (screen_info->dri_time > g_get_monotonic_time())
+    configs = glXChooseFBConfig(myScreenGetXDisplay (screen_info),
+                                screen_info->screen,
+                                visual_attribs,
+                                &n_configs);
+    if (configs == NULL)
     {
-        return;
+        g_warning ("Cannot retrieve frame buffer config, vsync disabled.");
+        return FALSE;
     }
 
-    vblank.request.sequence = 1;
-    vblank.request.type = _DRM_VBLANK_RELATIVE;
-    if (screen_info->dri_secondary)
+    fb_match = FALSE;
+    xvisual_id = XVisualIDFromVisual (screen_info->visual);
+    for (i = 0; i < n_configs; i++)
     {
-        vblank.request.type |= _DRM_VBLANK_SECONDARY;
+        XVisualInfo *visual_info;
+
+        visual_info = glXGetVisualFromFBConfig (myScreenGetXDisplay (screen_info),
+                                                configs[i]);
+        if (visual_info == NULL)
+        {
+            continue;
+        }
+        if (visual_info->visualid == xvisual_id)
+        {
+            fb_config = configs[i];
+            fb_match = TRUE;
+            XFree (visual_info);
+            break;
+        }
+
+        XFree (visual_info);
     }
+    XFree(configs);
 
-    do
+    if (fb_match == FALSE)
     {
-       retval = ioctl (screen_info->dri_fd, DRM_IOCTL_WAIT_VBLANK, &vblank);
-       vblank.request.type &= ~_DRM_VBLANK_RELATIVE;
+        g_warning ("Cannot find a matching visual for the frame buffer config, vsync disabled.");
+        return FALSE;
     }
-    while (retval == -1 && errno == EINTR);
 
-    screen_info->vblank_time = g_get_monotonic_time ();
+    screen_info->has_glx_sync_control =
+        epoxy_has_glx_extension (myScreenGetXDisplay (screen_info),
+                                 screen_info->screen,
+                                 "GLX_OML_sync_control");
+
+    screen_info->has_glx_video_sync =
+        epoxy_has_glx_extension (myScreenGetXDisplay (screen_info),
+                                 screen_info->screen,
+                                 "GLX_SGI_video_sync");
 
-    if (retval == -1)
+    if (!screen_info->has_glx_video_sync && !screen_info->has_glx_sync_control)
     {
-        if (screen_info->dri_success)
-        {
-            screen_info->dri_success = FALSE;
-            g_warning ("Error waiting on vblank with DRI: %s", g_strerror (errno));
-        }
+        g_warning ("Screen is missing required GLX extension, vsync disabled.");
+        return FALSE;
+    }
 
-        /* if getting the vblank fails, try to get it from the other output */
-        screen_info->dri_secondary = !screen_info->dri_secondary;
+    screen_info->glx_context = glXCreateNewContext(myScreenGetXDisplay (screen_info),
+                                                   fb_config,
+                                                   GLX_RGBA_TYPE,
+                                                   0,
+                                                   TRUE);
 
-        /* the output that we tried to get the vblank from might be disabled,
-           if that's the case, the device needs to be reopened, or it will continue to fail */
-        close_dri (screen_info);
-        open_dri (screen_info);
+    screen_info->glx_window = glXCreateWindow (myScreenGetXDisplay (screen_info),
+                                               fb_config,
+                                               screen_info->output,
+                                               NULL);
 
-        /* retry in 10 seconds */
-        screen_info->dri_time = g_get_monotonic_time() + TIMEOUT_DRI * 1000000;
-    }
-    else if (!screen_info->dri_success)
-    {
-        g_message ("Using vertical blank of %s DRI output",
-                   screen_info->dri_secondary ? "secondary" : "primary");
+    glXMakeContextCurrent (myScreenGetXDisplay (screen_info),
+                           screen_info->glx_window,
+                           screen_info->glx_window,
+                           screen_info->glx_context);
 
-        screen_info->dri_success = TRUE;
-    }
+    return TRUE;
 }
 
-#endif /* TIMEOUT_REPAINT */
-
-#endif /* HAVE_LIBDRM */
-
-#ifdef HAVE_RANDR
 static void
-get_refresh_rate (ScreenInfo* screen_info)
+wait_vblank (ScreenInfo *screen_info)
 {
-    gint refresh_rate;
-    XRRScreenConfiguration* randr_info;
+    guint32 current_count;
+    GLXDrawable  drawable;
 
-    randr_info = XRRGetScreenInfo (screen_info->display_info->dpy, screen_info->xroot);
-    refresh_rate = XRRConfigCurrentRate (randr_info);
-    XRRFreeScreenConfigInfo (randr_info);
+    if (screen_info->has_glx_sync_control)
+    {
+        gint64 ust, msc, sbc;
 
-    if (refresh_rate != screen_info->refresh_rate)
+        glXGetSyncValuesOML (myScreenGetXDisplay (screen_info),
+                             screen_info->glx_window,
+                             &ust, &msc, &sbc);
+        glXWaitForMscOML (myScreenGetXDisplay (screen_info),
+                          screen_info->glx_window,
+                          0, 2, (msc + 1) % 2,
+                          &ust, &msc, &sbc);
+    }
+    else if (screen_info->has_glx_video_sync)
     {
-        DBG ("Detected refreshrate: %i hertz", refresh_rate);
-        screen_info->refresh_rate = refresh_rate;
+        glXGetVideoSyncSGI (&current_count);
+        glXWaitVideoSyncSGI (2, (current_count + 1) % 2, &current_count);
     }
 }
-#endif /* HAVE_RANDR */
+#endif /* HAVE_EPOXY */
 
 static void
 paint_all (ScreenInfo *screen_info, XserverRegion region)
@@ -1400,12 +1410,6 @@ paint_all (ScreenInfo *screen_info, XserverRegion region)
     gint screen_height;
     CWindow *cw;
 
-#ifdef HAVE_LIBDRM
-#if TIMEOUT_REPAINT
-    gboolean use_dri;
-#endif /* TIMEOUT_REPAINT */
-#endif /* HAVE_LIBDRM */
-
     TRACE ("entering paint_all");
     g_return_if_fail (screen_info);
 
@@ -1566,32 +1570,17 @@ paint_all (ScreenInfo *screen_info, XserverRegion region)
         /* Set clipping back to the given region */
         XFixesSetPictureClipRegion (dpy, screen_info->rootBuffer, 0, 0, region);
     }
-#ifdef HAVE_LIBDRM
-#if TIMEOUT_REPAINT
-    use_dri = dri_enabled (screen_info);
-
-    if (use_dri)
+#ifdef HAVE_EPOXY
+    if (vblank_enabled (screen_info))
     {
-        /* sync all previous rendering commands, tell xlib to render the pixmap
-         * onto the root window, wait for the vblank, then flush, this minimizes
-         * tearing*/
         XFlush (dpy);
+        wait_vblank (screen_info);
     }
-#endif /* TIMEOUT_REPAINT */
-#endif /* HAVE_LIBDRM */
+#endif /* HAVE_EPOXY */
 
     XRenderComposite (dpy, PictOpSrc, screen_info->rootBuffer, None, screen_info->rootPicture,
                       0, 0, 0, 0, 0, 0, screen_width, screen_height);
-
-#ifdef HAVE_LIBDRM
-#if TIMEOUT_REPAINT
-    if (use_dri)
-    {
-        wait_vblank (screen_info);
-        XFlush (dpy);
-    }
-#endif /* TIMEOUT_REPAINT */
-#endif /* HAVE_LIBDRM */
+    XFlush (dpy);
 
     XFixesDestroyRegion (dpy, paint_region);
 }
@@ -1652,57 +1641,9 @@ static void
 add_repair (ScreenInfo *screen_info)
 {
 #if TIMEOUT_REPAINT
-#ifdef HAVE_LIBDRM
-    gint64 interval;
-#endif /* HAVE_LIBDRM */
-
-    if (screen_info->compositor_timeout_id != 0)
-    {
-        return;
-    }
-
-#ifdef HAVE_LIBDRM
-    if (dri_enabled (screen_info))
-    {
-        /* schedule the next render to be half a refresh period after the last vertical blank,
-           but at least 1 ms in the future so that all queued events can be processed,
-           and to reduce latency if we didn't render for a while */
-#ifdef HAVE_RANDR
-        if (screen_info->refresh_rate > 0)
-        {
-            interval = (screen_info->vblank_time + 500000 / screen_info->refresh_rate -
-                        g_get_monotonic_time ()) / 1000;
-        }
-        else
-#endif /* HAVE_RANDR */
-        {
-            interval = TIMEOUT_REPAINT - ((g_get_monotonic_time () - screen_info->vblank_time) / 1000);
-        }
-
-        if (interval > TIMEOUT_REPAINT_MAX)
-        {
-            interval = TIMEOUT_REPAINT_MAX;
-        }
-        else if (interval < TIMEOUT_REPAINT_MIN)
-        {
-            interval = TIMEOUT_REPAINT_MIN;
-        }
-    }
-    else
-    {
-        interval = TIMEOUT_REPAINT;
-    }
-#endif /* HAVE_LIBDRM */
-
     screen_info->compositor_timeout_id =
-#ifdef HAVE_LIBDRM
-        g_timeout_add (interval,
-                       compositor_timeout_cb, screen_info);
-#else
         g_timeout_add (TIMEOUT_REPAINT,
                        compositor_timeout_cb, screen_info);
-#endif /*HAVE_LIBDRM */
-
 #endif /* TIMEOUT_REPAINT */
 }
 
@@ -2844,25 +2785,6 @@ compositorHandleShapeNotify (DisplayInfo *display_info, XShapeEvent *ev)
     }
 }
 
-#ifdef HAVE_RANDR
-static void
-compositorHandleRandrNotify (DisplayInfo *display_info, XRRScreenChangeNotifyEvent *ev)
-{
-    ScreenInfo *screen_info;
-
-    g_return_if_fail (display_info != NULL);
-    g_return_if_fail (ev != NULL);
-    TRACE ("entering compositorHandleRandrNotify for 0x%lx", ev->window);
-
-    screen_info = myDisplayGetScreenFromRoot (display_info, ev->window);
-    if (screen_info)
-    {
-        get_refresh_rate (screen_info);
-    }
-    /* No need for RRUpdateConfiguration() here, leave that to gtk+ */
-}
-#endif /* HAVE_RANDR */
-
 static gboolean
 compositorCheckCMSelection (ScreenInfo *screen_info)
 {
@@ -3266,12 +3188,6 @@ compositorHandleEvent (DisplayInfo *display_info, XEvent *ev)
     {
         compositorHandleShapeNotify (display_info, (XShapeEvent *) ev);
     }
-#ifdef HAVE_RANDR
-    else if (ev->type == (display_info->xrandr_event_base + RRScreenChangeNotify))
-    {
-        compositorHandleRandrNotify (display_info, (XRRScreenChangeNotifyEvent *) ev);
-    }
-#endif /* HAVE_RANDR */
 
 #if TIMEOUT_REPAINT == 0
     repair_display (display_info);
@@ -3297,14 +3213,6 @@ compositorZoomIn (ScreenInfo *screen_info, XButtonEvent *ev)
     if (!screen_info->zoom_timeout_id)
     {
         int timeout_rate = 30; /* per second */
-#ifdef HAVE_RANDR
-        if (screen_info->display_info->have_xrandr)
-        {
-            timeout_rate = screen_info->refresh_rate / 2;
-            if (timeout_rate < 1)
-                timeout_rate = 30;
-        }
-#endif /* HAVE_RANDR */
         screen_info->zoom_timeout_id = g_timeout_add ((1000 / timeout_rate),
                                                       zoom_timeout_cb, screen_info);
     }
@@ -3543,21 +3451,11 @@ compositorManageScreen (ScreenInfo *screen_info)
     XClearArea (display_info->dpy, screen_info->output, 0, 0, 0, 0, TRUE);
     TRACE ("Manual compositing enabled");
 
-#ifdef HAVE_LIBDRM
-    open_dri (screen_info);
-    screen_info->dri_success = TRUE;
-    screen_info->dri_secondary = FALSE;
-    screen_info->dri_time = 0;
-    screen_info->vblank_time = 0;
-
-#ifdef HAVE_RANDR
-    if (display_info->have_xrandr)
-    {
-        get_refresh_rate(screen_info);
-        XRRSelectInput(display_info->dpy, screen_info->xroot, RRScreenChangeNotifyMask);
-    }
-#endif /* HAVE_RANDR */
-#endif /* HAVE_LIBDRM */
+#ifdef HAVE_EPOXY
+    screen_info->glx_context = None;
+    screen_info->glx_window = None;
+    vblank_init (screen_info);
+#endif /* HAVE_EPOXY */
 
     return TRUE;
 #else
@@ -3643,6 +3541,19 @@ compositorUnmanageScreen (ScreenInfo *screen_info)
         g_free (screen_info->gaussianMap);
         screen_info->gaussianMap = NULL;
     }
+#ifdef HAVE_EPOXY
+    if (screen_info->glx_context)
+    {
+        glXDestroyContext (display_info->dpy, screen_info->glx_context);
+        screen_info->glx_context = None;
+    }
+
+    if (screen_info->glx_window)
+    {
+        glXDestroyWindow (display_info->dpy, screen_info->glx_window);
+        screen_info->glx_window = None;
+    }
+#endif /* HAVE_EPOXY */
 
     screen_info->gaussianSize = -1;
     screen_info->wins_unredirected = 0;
@@ -3651,18 +3562,6 @@ compositorUnmanageScreen (ScreenInfo *screen_info)
                                     display_info->composite_mode);
 
     compositorSetCMSelection (screen_info, None);
-
-#ifdef HAVE_LIBDRM
-    close_dri (screen_info);
-
-#ifdef HAVE_RANDR
-    if (display_info->have_xrandr)
-    {
-        XRRSelectInput (display_info->dpy, screen_info->xroot, 0);
-    }
-#endif /* HAVE_RANDR */
-#endif /* HAVE_LIBDRM */
-
 #endif /* HAVE_COMPOSITOR */
 }
 
diff --git a/src/screen.h b/src/screen.h
index 9aeffc4..596dafa 100644
--- a/src/screen.h
+++ b/src/screen.h
@@ -32,12 +32,18 @@
 #include <xfconf/xfconf.h>
 #include <libxfce4kbd-private/xfce-shortcuts-provider.h>
 
-
 #ifdef HAVE_LIBSTARTUP_NOTIFICATION
 #define SN_API_NOT_YET_FROZEN
 #include <libsn/sn.h>
 #endif
 
+#ifdef HAVE_COMPOSITOR
+#ifdef HAVE_EPOXY
+#include <epoxy/gl.h>
+#include <epoxy/glx.h>
+#endif /* HAVE_EPOXY */
+#endif /* HAVE_COMPOSITOR */
+
 #ifndef INC_SCREEN_H
 #define INC_SCREEN_H
 
@@ -188,17 +194,12 @@ struct _ScreenInfo
     gboolean zoomed;
     guint zoom_timeout_id;
 
-#ifdef HAVE_LIBDRM
-    gint dri_fd;
-    gboolean dri_secondary;
-    gboolean dri_success;
-    gint64 dri_time;
-    gint64 vblank_time;
-#endif /* HAVE_LIBDRM */
-
-#ifdef HAVE_RANDR
-    gint refresh_rate;
-#endif /* HAVE_RANDR */
+#ifdef HAVE_EPOXY
+    gboolean has_glx_sync_control;
+    gboolean has_glx_video_sync;
+    GLXContext glx_context;
+    GLXWindow glx_window;
+#endif /* HAVE_EPOXY */
 
 #endif /* HAVE_COMPOSITOR */
 };

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the Xfce4-commits mailing list