[Xfce4-commits] <xfwm4:master> Add Vsync support for the compositor (bug #8898).
Nick Schermer
noreply at xfce.org
Wed May 8 21:18:02 CEST 2013
Updating branch refs/heads/master
to 22d6df280117fba8eb7584bca631d73a7ba359e2 (commit)
from 703bd36d23974c195ff0877c13b5bcfc2d56623c (commit)
commit 22d6df280117fba8eb7584bca631d73a7ba359e2
Author: Bob Loosen <bob.loosen at gmail.com>
Date: Wed May 8 21:08:46 2013 +0200
Add Vsync support for the compositor (bug #8898).
configure.ac.in | 9 +
defaults/defaults | 1 +
settings-dialogs/tweaks-settings.c | 9 +
settings-dialogs/xfwm4-tweaks-dialog.glade | 40 +++--
src/Makefile.am | 3 +-
src/compositor.c | 255 +++++++++++++++++++++++++++-
src/screen.h | 13 ++
src/settings.c | 7 +
src/settings.h | 1 +
9 files changed, 324 insertions(+), 14 deletions(-)
diff --git a/configure.ac.in b/configure.ac.in
index 9aa2617..9d90dac 100644
--- a/configure.ac.in
+++ b/configure.ac.in
@@ -19,6 +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])
dnl init autoconf
AC_COPYRIGHT([Copyright (c) 2002-2011
@@ -90,6 +91,14 @@ XDT_CHECK_PACKAGE([DBUS], [dbus-1], [1.0.0])
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])
+
+dnl
dnl Startup notification support
dnl
LIBSTARTUP_NOTIFICATION_FOUND="no"
diff --git a/defaults/defaults b/defaults/defaults
index 6db210a..17dc3d7 100644
--- a/defaults/defaults
+++ b/defaults/defaults
@@ -49,6 +49,7 @@ snap_resist=false
snap_to_border=true
snap_to_windows=false
snap_width=10
+sync_to_vblank=false
theme=Default
tile_on_move=true
title_alignment=center
diff --git a/settings-dialogs/tweaks-settings.c b/settings-dialogs/tweaks-settings.c
index f60b606..0b6a7eb 100644
--- a/settings-dialogs/tweaks-settings.c
+++ b/settings-dialogs/tweaks-settings.c
@@ -205,6 +205,7 @@ wm_tweaks_dialog_configure_widgets (GtkBuilder *builder)
GtkWidget *show_frame_shadow_check = GTK_WIDGET (gtk_builder_get_object (builder, "show_frame_shadow_check"));
GtkWidget *show_popup_shadow_check = GTK_WIDGET (gtk_builder_get_object (builder, "show_popup_shadow_check"));
GtkWidget *show_dock_shadow_check = GTK_WIDGET (gtk_builder_get_object (builder, "show_dock_shadow_check"));
+ GtkWidget *sync_to_vblank_check = GTK_WIDGET (gtk_builder_get_object (builder, "sync_to_vblank_check"));
GtkWidget *frame_opacity_scale = GTK_WIDGET (gtk_builder_get_object (builder, "frame_opacity_scale"));
GtkWidget *inactive_opacity_scale = GTK_WIDGET (gtk_builder_get_object (builder, "inactive_opacity_scale"));
@@ -405,6 +406,14 @@ wm_tweaks_dialog_configure_widgets (GtkBuilder *builder)
"/general/show_dock_shadow",
G_TYPE_BOOLEAN,
(GObject *)show_dock_shadow_check, "active");
+#ifdef HAVE_LIBDRM
+ xfconf_g_property_bind (xfwm4_channel,
+ "/general/sync_to_vblank",
+ G_TYPE_BOOLEAN,
+ (GObject *)sync_to_vblank_check, "active");
+#else
+ gtk_widget_hide (sync_to_vblank_check);
+#endif
xfconf_g_property_bind (xfwm4_channel,
"/general/frame_opacity",
diff --git a/settings-dialogs/xfwm4-tweaks-dialog.glade b/settings-dialogs/xfwm4-tweaks-dialog.glade
index e9996af..d026dfd 100644
--- a/settings-dialogs/xfwm4-tweaks-dialog.glade
+++ b/settings-dialogs/xfwm4-tweaks-dialog.glade
@@ -840,8 +840,8 @@ when switching via keyboard shortcuts</property>
</packing>
</child>
<child>
- <object class="GtkCheckButton" id="show_frame_shadow_check">
- <property name="label" translatable="yes">Show shadows under _regular windows</property>
+ <object class="GtkCheckButton" id="sync_to_vblank_check">
+ <property name="label" translatable="yes">Synchronize drawing to the _vertical blank</property>
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
@@ -888,6 +888,22 @@ when switching via keyboard shortcuts</property>
</packing>
</child>
<child>
+ <object class="GtkCheckButton" id="show_frame_shadow_check">
+ <property name="label" translatable="yes">Show shadows under _regular windows</property>
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">4</property>
+ </packing>
+ </child>
+ <child>
<object class="GtkLabel" id="label12">
<property name="visible">True</property>
<property name="can_focus">False</property>
@@ -899,7 +915,7 @@ when switching via keyboard shortcuts</property>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
- <property name="position">4</property>
+ <property name="position">5</property>
</packing>
</child>
<child>
@@ -959,7 +975,7 @@ when switching via keyboard shortcuts</property>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
- <property name="position">5</property>
+ <property name="position">6</property>
</packing>
</child>
<child>
@@ -974,7 +990,7 @@ when switching via keyboard shortcuts</property>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
- <property name="position">6</property>
+ <property name="position">7</property>
</packing>
</child>
<child>
@@ -1034,7 +1050,7 @@ when switching via keyboard shortcuts</property>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
- <property name="position">7</property>
+ <property name="position">8</property>
</packing>
</child>
<child>
@@ -1049,7 +1065,7 @@ when switching via keyboard shortcuts</property>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
- <property name="position">8</property>
+ <property name="position">9</property>
</packing>
</child>
<child>
@@ -1109,7 +1125,7 @@ when switching via keyboard shortcuts</property>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
- <property name="position">9</property>
+ <property name="position">10</property>
</packing>
</child>
<child>
@@ -1124,7 +1140,7 @@ when switching via keyboard shortcuts</property>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
- <property name="position">10</property>
+ <property name="position">11</property>
</packing>
</child>
<child>
@@ -1184,7 +1200,7 @@ when switching via keyboard shortcuts</property>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
- <property name="position">11</property>
+ <property name="position">12</property>
</packing>
</child>
<child>
@@ -1199,7 +1215,7 @@ when switching via keyboard shortcuts</property>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
- <property name="position">12</property>
+ <property name="position">13</property>
</packing>
</child>
<child>
@@ -1259,7 +1275,7 @@ when switching via keyboard shortcuts</property>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
- <property name="position">13</property>
+ <property name="position">14</property>
</packing>
</child>
</object>
diff --git a/src/Makefile.am b/src/Makefile.am
index f92e3f9..ee2fff6 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -80,6 +80,7 @@ xfwm4_CFLAGS = \
$(LIBXFCE4UI_CFLAGS) \
$(LIBXFCE4KBD_PRIVATE_CFLAGS) \
$(RENDER_CFLAGS) \
+ $(LIBDRM_CFLAGS) \
$(LIBSTARTUP_NOTIFICATION_CFLAGS) \
$(COMPOSITOR_CFLAGS) \
-DPACKAGE_LOCALE_DIR=\"$(localedir)\" \
@@ -101,7 +102,7 @@ xfwm4_LDADD = \
$(RENDER_LIBS) \
$(COMPOSITOR_LIBS) \
$(RANDR_LIBS) \
- $(MATH_LIBS)
+ $(MATH_LIBS)
EXTRA_DIST = \
default_icon.png \
diff --git a/src/compositor.c b/src/compositor.c
index 428989c..03607d0 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -36,6 +36,14 @@
#include <string.h>
#include <libxfce4util/libxfce4util.h>
+#ifdef HAVE_LIBDRM
+#include <stdint.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <drm.h>
+#include <stropts.h>
+#endif /* HAVE_LIBDRM */
+
#include "display.h"
#include "screen.h"
#include "client.h"
@@ -86,7 +94,12 @@
#define WIN_IS_REDIRECTED(cw) (cw->redirected)
/* Set TIMEOUT_REPAINT to 0 to disable timeout repaint */
-#define TIMEOUT_REPAINT 10 /* msec.) */
+#define TIMEOUT_REPAINT 10 /* msec */
+#define TIMEOUT_REPAINT_MIN 1
+#define TIMEOUT_REPAINT_MAX 20
+#define TIMEOUT_DRI 10 /* seconds */
+
+#define DRM_CARD0 "/dev/dri/card0"
typedef struct _CWindow CWindow;
struct _CWindow
@@ -1247,6 +1260,113 @@ 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;
+ }
+}
+
+static gboolean
+dri_enabled (ScreenInfo *screen_info)
+{
+ return (screen_info->dri_fd != -1 && screen_info->params->sync_to_vblank);
+}
+
+static void
+wait_vblank (ScreenInfo *screen_info)
+{
+ int retval;
+ drm_wait_vblank_t vblank;
+
+ if (screen_info->dri_time > g_get_monotonic_time())
+ {
+ return;
+ }
+
+ vblank.request.sequence = 1;
+ vblank.request.type = _DRM_VBLANK_RELATIVE;
+ if (screen_info->dri_secondary)
+ {
+ vblank.request.type |= _DRM_VBLANK_SECONDARY;
+ }
+
+ do
+ {
+ retval = ioctl (screen_info->dri_fd, DRM_IOCTL_WAIT_VBLANK, &vblank);
+ vblank.request.type &= ~_DRM_VBLANK_RELATIVE;
+ }
+ while (retval == -1 && errno == EINTR);
+
+ screen_info->vblank_time = g_get_monotonic_time ();
+
+ if (retval == -1)
+ {
+ if (screen_info->dri_success)
+ {
+ screen_info->dri_success = FALSE;
+ g_warning ("Error waiting on vblank with DRI: %s", g_strerror (errno));
+ }
+
+ /* if getting the vblank fails, try to get it from the other output */
+ screen_info->dri_secondary = !screen_info->dri_secondary;
+
+ /* 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);
+
+ /* 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");
+
+ screen_info->dri_success = TRUE;
+ }
+}
+
+#ifdef HAVE_RANDR
+static void
+get_refresh_rate (ScreenInfo* screen_info)
+{
+ gint refresh_rate;
+ XRRScreenConfiguration* randr_info;
+
+ randr_info = XRRGetScreenInfo (screen_info->display_info->dpy, screen_info->xroot);
+ refresh_rate = XRRConfigCurrentRate (randr_info);
+ XRRFreeScreenConfigInfo (randr_info);
+
+ if (refresh_rate != screen_info->refresh_rate)
+ {
+ g_message ("Detected refreshrate:%i hertz", refresh_rate);
+ screen_info->refresh_rate = refresh_rate;
+ }
+}
+#endif /* HAVE_RANDR */
+
+#endif /* TIMEOUT_REPAINT */
+
+#endif /* HAVE_LIBDRM */
+
static void
paint_all (ScreenInfo *screen_info, XserverRegion region)
{
@@ -1258,6 +1378,12 @@ 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);
@@ -1406,8 +1532,34 @@ paint_all (ScreenInfo *screen_info, XserverRegion region)
TRACE ("Copying data back to screen");
/* 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)
+ {
+ /* 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);
+ }
+#endif /* TIMEOUT_REPAINT */
+#endif /* HAVE_LIBDRM */
+
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 */
+
XFixesDestroyRegion (dpy, paint_region);
}
@@ -1467,13 +1619,57 @@ 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 */
}
@@ -2543,6 +2739,26 @@ compositorHandleShapeNotify (DisplayInfo *display_info, XShapeEvent *ev)
}
}
+#ifdef HAVE_LIBDRM
+#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);
+
+ XRRUpdateConfiguration ((XEvent *) ev);
+}
+#endif /* HAVE_RANDR */
+#endif /* HAVE_LIBDRM */
+
static void
compositorSetCMSelection (ScreenInfo *screen_info, Window w)
{
@@ -2753,6 +2969,15 @@ compositorHandleEvent (DisplayInfo *display_info, XEvent *ev)
{
compositorHandleShapeNotify (display_info, (XShapeEvent *) ev);
}
+#ifdef HAVE_LIBDRM
+#ifdef HAVE_RANDR
+ else if (ev->type == (display_info->xrandr_event_base + RRScreenChangeNotify))
+ {
+ compositorHandleRandrNotify (display_info, (XRRScreenChangeNotifyEvent *) ev);
+ }
+#endif /* HAVE_RANDR */
+#endif /* HAVE_LIBDRM */
+
#if TIMEOUT_REPAINT == 0
repair_display (display_info);
#endif /* TIMEOUT_REPAINT */
@@ -2971,6 +3196,22 @@ compositorManageScreen (ScreenInfo *screen_info)
compositorSetCMSelection (screen_info, screen_info->xfwm4_win);
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 */
+
return TRUE;
#else
return FALSE;
@@ -3063,6 +3304,18 @@ 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 88e4845..a2b25c0 100644
--- a/src/screen.h
+++ b/src/screen.h
@@ -181,6 +181,19 @@ struct _ScreenInfo
gboolean damages_pending;
guint compositor_timeout_id;
+
+#ifdef HAVE_LIBDRM
+ gint dri_fd;
+ gboolean dri_secondary;
+ gboolean dri_success;
+ gint64 dri_time;
+ gint64 vblank_time;
+
+#ifdef HAVE_RANDR
+ gint refresh_rate;
+#endif /* HAVE_RANDR */
+#endif /* HAVE_LIBDRM */
+
#endif /* HAVE_COMPOSITOR */
};
diff --git a/src/settings.c b/src/settings.c
index 607bb7b..a8a9e06 100644
--- a/src/settings.c
+++ b/src/settings.c
@@ -720,6 +720,7 @@ loadSettings (ScreenInfo *screen_info)
{"snap_to_border", NULL, G_TYPE_BOOLEAN, TRUE},
{"snap_to_windows", NULL, G_TYPE_BOOLEAN, TRUE},
{"snap_width", NULL, G_TYPE_INT, TRUE},
+ {"sync_to_vblank", NULL, G_TYPE_BOOLEAN, TRUE},
{"theme", NULL, G_TYPE_STRING, TRUE},
{"tile_on_move", NULL, G_TYPE_BOOLEAN, TRUE},
{"title_alignment", NULL, G_TYPE_STRING, TRUE},
@@ -823,6 +824,8 @@ loadSettings (ScreenInfo *screen_info)
getBoolValue ("snap_resist", rc);
screen_info->params->snap_width =
getIntValue ("snap_width", rc);
+ screen_info->params->sync_to_vblank =
+ getBoolValue ("sync_to_vblank", rc);
screen_info->params->tile_on_move =
getBoolValue ("tile_on_move", rc);
screen_info->params->toggle_workspaces =
@@ -1329,6 +1332,10 @@ cb_xfwm4_channel_property_changed(XfconfChannel *channel, const gchar *property_
{
screen_info->params->tile_on_move = g_value_get_boolean (value);
}
+ else if (!strcmp (name, "sync_to_vblank"))
+ {
+ screen_info->params->sync_to_vblank = g_value_get_boolean (value);
+ }
else if (!strcmp (name, "toggle_workspaces"))
{
screen_info->params->toggle_workspaces = g_value_get_boolean (value);
diff --git a/src/settings.h b/src/settings.h
index be01b6b..d595ddc 100644
--- a/src/settings.h
+++ b/src/settings.h
@@ -223,6 +223,7 @@ struct _XfwmParams
gboolean snap_resist;
gboolean snap_to_border;
gboolean snap_to_windows;
+ gboolean sync_to_vblank;
gboolean tile_on_move;
gboolean title_vertical_offset_active;
gboolean title_vertical_offset_inactive;
More information about the Xfce4-commits
mailing list