diff -Naur xfwm4-4.10.0.orig/defaults/defaults xfwm4-4.10.0/defaults/defaults --- xfwm4-4.10.0.orig/defaults/defaults 2012-04-28 22:56:34.000000000 +0200 +++ xfwm4-4.10.0/defaults/defaults 2012-05-25 12:57:39.469499938 +0200 @@ -49,6 +49,7 @@ 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 -Naur xfwm4-4.10.0.orig/settings-dialogs/tweaks-settings.c xfwm4-4.10.0/settings-dialogs/tweaks-settings.c --- xfwm4-4.10.0.orig/settings-dialogs/tweaks-settings.c 2012-04-28 22:56:34.000000000 +0200 +++ xfwm4-4.10.0/settings-dialogs/tweaks-settings.c 2012-05-25 12:57:39.469499938 +0200 @@ -205,6 +205,7 @@ 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,10 @@ "/general/show_dock_shadow", G_TYPE_BOOLEAN, (GObject *)show_dock_shadow_check, "active"); + xfconf_g_property_bind (xfwm4_channel, + "/general/sync_to_vblank", + G_TYPE_BOOLEAN, + (GObject *)sync_to_vblank_check, "active"); xfconf_g_property_bind (xfwm4_channel, "/general/frame_opacity", diff -Naur xfwm4-4.10.0.orig/src/compositor.c xfwm4-4.10.0/src/compositor.c --- xfwm4-4.10.0.orig/src/compositor.c 2012-04-28 22:56:34.000000000 +0200 +++ xfwm4-4.10.0/src/compositor.c 2012-05-25 12:57:39.470499954 +0200 @@ -36,6 +36,11 @@ #include #include +#include +#include +#include +#include + #include "display.h" #include "screen.h" #include "client.h" @@ -87,6 +92,8 @@ /* Set TIMEOUT_REPAINT to 0 to disable timeout repaint */ #define TIMEOUT_REPAINT 10 /* msec.) */ +#define TIMEOUT_REPAINT_MIN 1 /* msec.) */ +#define TIMEOUT_DRI 10 /* seconds */ typedef struct _CWindow CWindow; struct _CWindow @@ -1243,6 +1250,72 @@ } } +#if TIMEOUT_REPAINT + +static void +open_dri (DisplayInfo *display_info) +{ + const char* dev = "/dev/dri/card0"; + display_info->dri_fd = open(dev, O_RDWR); + if (display_info->dri_fd == -1) + g_warning ("Error opening %s: %s", dev, strerror(errno)); +} + +static void +close_dri (DisplayInfo *display_info) +{ + close(display_info->dri_fd); + display_info->dri_fd = -1; +} + +static gboolean +dri_enabled (ScreenInfo *screen_info) +{ + return (screen_info->display_info->dri_fd != -1 && screen_info->params->sync_to_vblank); +} + +static void +wait_vblank (DisplayInfo *display_info) +{ + int retval; + drm_wait_vblank_t vblank; + + if (display_info->dri_time > g_get_monotonic_time()) + return; + + vblank.request.sequence = 1; + vblank.request.type = _DRM_VBLANK_RELATIVE; + if (display_info->dri_secondary) + vblank.request.type |= _DRM_VBLANK_SECONDARY; + + do + { + retval = ioctl(display_info->dri_fd, DRM_IOCTL_WAIT_VBLANK, &vblank); + vblank.request.type &= ~_DRM_VBLANK_RELATIVE; + } + while (retval == -1 && errno == EINTR); + + display_info->vblank_time = g_get_monotonic_time(); + + if (retval == -1) + { + /* if getting the vblank fails, try to get it from the other output */ + display_info->dri_secondary = !display_info->dri_secondary; + g_warning ("Error waiting on vblank with DRI:%s, trying %s output", + strerror(errno), display_info->dri_secondary ? "secondary" : "primary"); + + /* 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(display_info); + open_dri(display_info); + + //retry again in 10 seconds + display_info->dri_time = g_get_monotonic_time() + TIMEOUT_DRI * 1000000; + } +} + +#endif + static void paint_all (ScreenInfo *screen_info, XserverRegion region) { @@ -1254,6 +1327,10 @@ gint screen_height; CWindow *cw; +#if TIMEOUT_REPAINT + gboolean use_dri; +#endif + TRACE ("entering paint_all"); g_return_if_fail (screen_info); @@ -1402,8 +1479,24 @@ TRACE ("Copying data back to screen"); /* Set clipping back to the given region */ XFixesSetPictureClipRegion (dpy, screen_info->rootBuffer, 0, 0, region); + +#if TIMEOUT_REPAINT + use_dri = dri_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*/ + if (use_dri) + XFlush(dpy); +#endif XRenderComposite (dpy, PictOpSrc, screen_info->rootBuffer, None, screen_info->rootPicture, 0, 0, 0, 0, 0, 0, screen_width, screen_height); +#if TIMEOUT_REPAINT + if (use_dri) + { + wait_vblank(screen_info->display_info); + XFlush(dpy); + } +#endif + XFixesDestroyRegion (dpy, paint_region); } @@ -1467,8 +1560,25 @@ { return; } + + gint64 interval; + if (dri_enabled(screen_info)) + { + /* schedule the next render to be 10 ms after the last vertical blank, + but at least 1 ms in the future so that all queued events can be processed */ + interval = TIMEOUT_REPAINT - ((g_get_monotonic_time() - screen_info->display_info->vblank_time) / 1000); + if (interval > TIMEOUT_REPAINT) /* sanity check */ + interval = TIMEOUT_REPAINT; + else if (interval < TIMEOUT_REPAINT_MIN) + interval = TIMEOUT_REPAINT_MIN; + } + else + { + interval = TIMEOUT_REPAINT; + } + screen_info->compositor_timeout_id = - g_timeout_add (TIMEOUT_REPAINT, + g_timeout_add (interval, compositor_timeout_cb, screen_info); #endif /* TIMEOUT_REPAINT */ } @@ -2841,6 +2951,11 @@ display_info->have_overlays = ((composite_major > 0) || (composite_minor >= 3)); #endif /* HAVE_OVERLAYS */ + display_info->dri_fd = -1; + display_info->dri_secondary = FALSE; + display_info->dri_time = 0; + display_info->vblank_time = 0; + #else /* HAVE_COMPOSITOR */ display_info->enable_compositor = FALSE; #endif /* HAVE_COMPOSITOR */ @@ -2967,6 +3082,8 @@ compositorSetCMSelection (screen_info, screen_info->xfwm4_win); TRACE ("Manual compositing enabled"); + open_dri(display_info); + return TRUE; #else return FALSE; @@ -3059,6 +3176,8 @@ display_info->composite_mode); compositorSetCMSelection (screen_info, None); + + close_dri(display_info); #endif /* HAVE_COMPOSITOR */ } diff -Naur xfwm4-4.10.0.orig/src/display.h xfwm4-4.10.0/src/display.h --- xfwm4-4.10.0.orig/src/display.h 2012-04-28 22:56:34.000000000 +0200 +++ xfwm4-4.10.0/src/display.h 2012-05-25 12:57:39.470499954 +0200 @@ -345,6 +345,11 @@ gboolean have_overlays; #endif /* HAVE_OVERLAYS */ + gint dri_fd; + gboolean dri_secondary; + gint64 dri_time; + gint64 vblank_time; + #endif /* HAVE_COMPOSITOR */ }; diff -Naur xfwm4-4.10.0.orig/src/settings.c xfwm4-4.10.0/src/settings.c --- xfwm4-4.10.0.orig/src/settings.c 2012-04-28 22:56:34.000000000 +0200 +++ xfwm4-4.10.0/src/settings.c 2012-05-25 13:03:20.325759094 +0200 @@ -720,6 +720,7 @@ {"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}, @@ -825,6 +826,8 @@ getIntValue ("snap_width", rc); screen_info->params->tile_on_move = getBoolValue ("tile_on_move", rc); + screen_info->params->sync_to_vblank = + getBoolValue ("sync_to_vblank", rc); screen_info->params->toggle_workspaces = getBoolValue ("toggle_workspaces", rc); screen_info->params->unredirect_overlays = @@ -1329,6 +1332,10 @@ { 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 -Naur xfwm4-4.10.0.orig/src/settings.h xfwm4-4.10.0/src/settings.h --- xfwm4-4.10.0.orig/src/settings.h 2012-04-28 22:56:34.000000000 +0200 +++ xfwm4-4.10.0/src/settings.h 2012-05-25 13:01:12.905415656 +0200 @@ -224,6 +224,7 @@ gboolean snap_to_border; gboolean snap_to_windows; gboolean tile_on_move; + gboolean sync_to_vblank; gboolean title_vertical_offset_active; gboolean title_vertical_offset_inactive; gboolean toggle_workspaces;