Blame SOURCES/0008-Add-support-for-quad-buffer-stereo.patch

e47e58
From 7940ea62307044c056c16f1534e3e8e94cc7a352 Mon Sep 17 00:00:00 2001
d1d875
From: "Owen W. Taylor" <otaylor@fishsoup.net>
d1d875
Date: Thu, 8 May 2014 18:44:15 -0400
e47e58
Subject: [PATCH 7/8] Add support for quad-buffer stereo
d1d875
d1d875
Track the stereo status of windows using the new EXT_stereo_tree
d1d875
GLX extension.
d1d875
d1d875
When stereo is enabled or disabled, a restart is triggered via
d1d875
meta_restart() after a timeout, setting a _META_ENABLE_STEREO
d1d875
property on the root window to indicate whether we should
d1d875
turn on a stereo stage for clutter. The property avoids a loop,
d1d875
since we need to enable stereo *before* initializing Clutter and GL,
d1d875
but we need GL to figure out whether we have stereo windows.
d1d875
d1d875
Stereo windows are drawn to the stage using new functionality
d1d875
in Cogl to setup a stereo context, select which buffer to draw
d1d875
to, and draw either the left or right buffer of a stereo
d1d875
texture_from_pixmap.
d1d875
---
d1d875
 src/Makefile.am                              |   2 +
d1d875
 src/compositor/compositor-private.h          |   9 ++
d1d875
 src/compositor/compositor.c                  | 128 ++++++++++++++++++++++
d1d875
 src/compositor/meta-shaped-texture-private.h |   5 +-
d1d875
 src/compositor/meta-shaped-texture.c         | 157 ++++++++++++++++++++-------
e47e58
 src/compositor/meta-surface-actor-wayland.c  |  10 +-
67f8b7
 src/compositor/meta-surface-actor-x11.c      |  56 ++++++++--
d1d875
 src/compositor/meta-surface-actor-x11.h      |   5 +
d1d875
 src/compositor/meta-window-actor-private.h   |   5 +
d1d875
 src/compositor/meta-window-actor.c           |  22 ++++
67f8b7
 src/core/main.c                              |   4 +
67f8b7
 src/core/stereo.c                            | 153 ++++++++++++++++++++++++++
d1d875
 src/core/stereo.h                            |  28 +++++
e47e58
 src/wayland/meta-wayland-surface.c           |   2 +-
e47e58
 14 files changed, 535 insertions(+), 51 deletions(-)
d1d875
 create mode 100644 src/core/stereo.c
d1d875
 create mode 100644 src/core/stereo.h
d1d875
d1d875
diff --git a/src/Makefile.am b/src/Makefile.am
e47e58
index 6aef50de8..8c680602c 100644
d1d875
--- a/src/Makefile.am
d1d875
+++ b/src/Makefile.am
e47e58
@@ -281,6 +281,8 @@ libmutter_@LIBMUTTER_API_VERSION@_la_SOURCES =	\
d1d875
 	core/stack.h				\
d1d875
 	core/stack-tracker.c			\
d1d875
 	core/stack-tracker.h			\
d1d875
+	core/stereo.c				\
d1d875
+	core/stereo.h				\
d1d875
 	core/util.c				\
d1d875
 	meta/util.h				\
d1d875
 	core/util-private.h			\
d1d875
diff --git a/src/compositor/compositor-private.h b/src/compositor/compositor-private.h
e47e58
index ba58bf175..1c257b5ee 100644
d1d875
--- a/src/compositor/compositor-private.h
d1d875
+++ b/src/compositor/compositor-private.h
d1d875
@@ -21,6 +21,10 @@ struct _MetaCompositor
d1d875
   gint64          server_time_query_time;
d1d875
   gint64          server_time_offset;
d1d875
 
d1d875
+  int             glx_opcode;
d1d875
+  guint           stereo_tree_ext : 1;
d1d875
+  guint           have_stereo_windows : 1;
d1d875
+
d1d875
   guint           server_time_is_monotonic_time : 1;
d1d875
   guint           no_mipmaps  : 1;
d1d875
 
e47e58
@@ -61,6 +65,11 @@ void     meta_end_modal_for_plugin   (MetaCompositor   *compositor,
d1d875
 gint64 meta_compositor_monotonic_time_to_server_time (MetaDisplay *display,
d1d875
                                                       gint64       monotonic_time);
d1d875
 
d1d875
+gboolean meta_compositor_window_is_stereo     (MetaScreen *screen,
d1d875
+                                               Window      xwindow);
d1d875
+void     meta_compositor_select_stereo_notify (MetaScreen *screen,
d1d875
+                                               Window      xwindow);
d1d875
+
67f8b7
 void meta_compositor_flash_window (MetaCompositor *compositor,
67f8b7
                                    MetaWindow     *window);
67f8b7
 
d1d875
diff --git a/src/compositor/compositor.c b/src/compositor/compositor.c
e47e58
index 17e8a55dd..a1bf1a8f8 100644
d1d875
--- a/src/compositor/compositor.c
d1d875
+++ b/src/compositor/compositor.c
67f8b7
@@ -70,6 +70,8 @@
d1d875
 #include "meta-window-group.h"
d1d875
 #include "window-private.h" /* to check window->hidden */
d1d875
 #include "display-private.h" /* for meta_display_lookup_x_window() and meta_display_cancel_touch() */
d1d875
+#include "stack-tracker.h"
d1d875
+#include "stereo.h"
d1d875
 #include "util-private.h"
e47e58
 #include "backends/meta-dnd-private.h"
d1d875
 #include "frame.h"
e47e58
@@ -482,6 +484,97 @@ redirect_windows (MetaScreen *screen)
d1d875
     }
d1d875
 }
d1d875
 
d1d875
+#define GLX_STEREO_TREE_EXT        0x20F5
d1d875
+#define GLX_STEREO_NOTIFY_MASK_EXT 0x00000001
d1d875
+#define GLX_STEREO_NOTIFY_EXT      0x00000000
d1d875
+
d1d875
+typedef struct {
d1d875
+  int type;
d1d875
+  unsigned long serial;
d1d875
+  Bool send_event;
d1d875
+  Display *display;
d1d875
+  int extension;
d1d875
+  int evtype;
d1d875
+  Drawable window;
d1d875
+  Bool stereo_tree;
d1d875
+} StereoNotifyEvent;
d1d875
+
d1d875
+static gboolean
d1d875
+screen_has_stereo_tree_ext (MetaScreen *screen)
d1d875
+{
d1d875
+  MetaDisplay *display = meta_screen_get_display (screen);
d1d875
+  Display     *xdisplay = meta_display_get_xdisplay (display);
d1d875
+  const char  *extensions_string;
d1d875
+
d1d875
+  static const char * (*query_extensions_string) (Display *display,
d1d875
+                                                  int      screen);
d1d875
+
d1d875
+  if (query_extensions_string == NULL)
d1d875
+    query_extensions_string =
d1d875
+      (const char * (*) (Display *, int))
d1d875
+      cogl_get_proc_address ("glXQueryExtensionsString");
d1d875
+
d1d875
+  extensions_string = query_extensions_string (xdisplay,
d1d875
+                                               meta_screen_get_screen_number (screen));
d1d875
+
e47e58
+  return extensions_string && strstr (extensions_string, "EXT_stereo_tree") != 0;
d1d875
+}
d1d875
+
d1d875
+#include <GL/gl.h>
d1d875
+
d1d875
+gboolean
d1d875
+meta_compositor_window_is_stereo (MetaScreen *screen,
d1d875
+                                  Window      xwindow)
d1d875
+{
d1d875
+  MetaCompositor *compositor = get_compositor_for_screen (screen);
d1d875
+  MetaDisplay    *display = meta_screen_get_display (screen);
d1d875
+  Display        *xdisplay = meta_display_get_xdisplay (display);
d1d875
+
d1d875
+  static int (*query_drawable) (Display      *dpy,
d1d875
+                                Drawable      draw,
d1d875
+                                int           attribute,
d1d875
+                                unsigned int *value);
d1d875
+
d1d875
+  if (compositor->stereo_tree_ext)
d1d875
+    {
d1d875
+      unsigned int stereo_tree = 0;
d1d875
+
d1d875
+      if (query_drawable == NULL)
d1d875
+        query_drawable =
d1d875
+          (int (*) (Display *, Drawable, int, unsigned int *))
d1d875
+          cogl_get_proc_address ("glXQueryDrawable");
d1d875
+
d1d875
+      query_drawable (xdisplay, xwindow, GLX_STEREO_TREE_EXT, &stereo_tree);
d1d875
+
d1d875
+      return stereo_tree != 0;
d1d875
+    }
d1d875
+  else
d1d875
+    return FALSE;
d1d875
+}
d1d875
+
d1d875
+void
d1d875
+meta_compositor_select_stereo_notify (MetaScreen *screen,
d1d875
+                                      Window      xwindow)
d1d875
+{
d1d875
+  MetaCompositor *compositor = get_compositor_for_screen (screen);
d1d875
+  MetaDisplay    *display = meta_screen_get_display (screen);
d1d875
+  Display        *xdisplay = meta_display_get_xdisplay (display);
d1d875
+
d1d875
+  static void (*select_event) (Display      *dpy,
d1d875
+                               Drawable      draw,
d1d875
+                               unsigned long event_mask);
d1d875
+
d1d875
+  if (compositor->stereo_tree_ext)
d1d875
+    {
d1d875
+      if (select_event == NULL)
d1d875
+        select_event =
d1d875
+          (void (*) (Display *, Drawable, unsigned long))
d1d875
+          cogl_get_proc_address ("glXSelectEvent");
d1d875
+
d1d875
+      select_event (xdisplay, xwindow, GLX_STEREO_NOTIFY_MASK_EXT);
d1d875
+    }
d1d875
+}
d1d875
+
d1d875
 void
d1d875
 meta_compositor_manage (MetaCompositor *compositor)
d1d875
 {
e47e58
@@ -490,6 +583,8 @@ meta_compositor_manage (MetaCompositor *compositor)
d1d875
   MetaScreen *screen = display->screen;
d1d875
   MetaBackend *backend = meta_get_backend ();
d1d875
 
d1d875
+  compositor->stereo_tree_ext = screen_has_stereo_tree_ext (screen);
d1d875
+
d1d875
   meta_screen_set_cm_selection (display->screen);
d1d875
 
d1d875
   compositor->stage = meta_backend_get_stage (backend);
e47e58
@@ -757,6 +852,23 @@ meta_compositor_process_event (MetaCompositor *compositor,
d1d875
       if (window)
d1d875
         process_damage (compositor, (XDamageNotifyEvent *) event, window);
d1d875
     }
d1d875
+  else if (!meta_is_wayland_compositor () &&
d1d875
+           event->type == GenericEvent &&
d1d875
+           event->xcookie.extension == compositor->glx_opcode)
d1d875
+    {
d1d875
+      if (event->xcookie.evtype == GLX_STEREO_NOTIFY_EXT)
d1d875
+        {
d1d875
+          StereoNotifyEvent *stereo_event = (StereoNotifyEvent *)(event->xcookie.data);
d1d875
+          window = meta_display_lookup_x_window (compositor->display, stereo_event->window);
d1d875
+
d1d875
+          if (window != NULL)
d1d875
+            {
d1d875
+              MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
d1d875
+              meta_window_actor_stereo_notify (window_actor, stereo_event->stereo_tree);
d1d875
+              meta_stack_tracker_queue_sync_stack (window->screen->stack_tracker);
d1d875
+            }
d1d875
+        }
d1d875
+    }
d1d875
 
d1d875
   if (compositor->have_x11_sync_object)
d1d875
     meta_sync_ring_handle_event (event);
e47e58
@@ -957,6 +1069,7 @@ meta_compositor_sync_stack (MetaCompositor  *compositor,
d1d875
 			    GList	    *stack)
d1d875
 {
d1d875
   GList *old_stack;
d1d875
+  int stereo_window_count = 0;
d1d875
 
d1d875
   /* This is painful because hidden windows that we are in the process
d1d875
    * of animating out of existence. They'll be at the bottom of the
e47e58
@@ -1032,6 +1145,8 @@ meta_compositor_sync_stack (MetaCompositor  *compositor,
d1d875
        * near the front of the other.)
d1d875
        */
d1d875
       compositor->windows = g_list_prepend (compositor->windows, actor);
d1d875
+      if (meta_window_actor_is_stereo (actor))
d1d875
+        stereo_window_count++;
d1d875
 
d1d875
       stack = g_list_remove (stack, window);
d1d875
       old_stack = g_list_remove (old_stack, actor);
e47e58
@@ -1039,6 +1154,8 @@ meta_compositor_sync_stack (MetaCompositor  *compositor,
d1d875
 
d1d875
   sync_actor_stacking (compositor);
e47e58
 
d1d875
+  meta_stereo_set_have_stereo_windows (stereo_window_count > 0);
e47e58
+
e47e58
   compositor->top_window_actor = get_top_visible_window_actor (compositor);
d1d875
 }
d1d875
 
e47e58
@@ -1237,6 +1354,17 @@ meta_compositor_new (MetaDisplay *display)
d1d875
                                            meta_post_paint_func,
d1d875
                                            compositor,
d1d875
                                            NULL);
d1d875
+  if (!meta_is_wayland_compositor ())
d1d875
+    {
d1d875
+      Display *xdisplay = meta_display_get_xdisplay (display);
d1d875
+      int glx_major_opcode, glx_first_event, glx_first_error;
d1d875
+
d1d875
+      if (XQueryExtension (xdisplay,
d1d875
+                           "GLX",
d1d875
+                           &glx_major_opcode, &glx_first_event, &glx_first_error))
d1d875
+        compositor->glx_opcode = glx_major_opcode;
d1d875
+    }
d1d875
+
d1d875
   return compositor;
d1d875
 }
d1d875
 
d1d875
diff --git a/src/compositor/meta-shaped-texture-private.h b/src/compositor/meta-shaped-texture-private.h
e47e58
index 5b3f283c2..189a95312 100644
d1d875
--- a/src/compositor/meta-shaped-texture-private.h
d1d875
+++ b/src/compositor/meta-shaped-texture-private.h
d1d875
@@ -30,8 +30,9 @@
d1d875
 #include <meta/meta-shaped-texture.h>
d1d875
 
d1d875
 ClutterActor *meta_shaped_texture_new (void);
d1d875
-void meta_shaped_texture_set_texture (MetaShapedTexture *stex,
d1d875
-                                      CoglTexture       *texture);
d1d875
+void meta_shaped_texture_set_textures (MetaShapedTexture *stex,
d1d875
+                                       CoglTexture       *texture,
d1d875
+                                       CoglTexture       *texture_right);
e47e58
 void meta_shaped_texture_set_is_y_inverted (MetaShapedTexture *stex,
e47e58
                                             gboolean           is_y_inverted);
e47e58
 void meta_shaped_texture_set_snippet (MetaShapedTexture *stex,
d1d875
diff --git a/src/compositor/meta-shaped-texture.c b/src/compositor/meta-shaped-texture.c
e47e58
index 98346c6ae..b89de03a3 100644
d1d875
--- a/src/compositor/meta-shaped-texture.c
d1d875
+++ b/src/compositor/meta-shaped-texture.c
d1d875
@@ -74,8 +74,10 @@ static guint signals[LAST_SIGNAL];
d1d875
 struct _MetaShapedTexturePrivate
d1d875
 {
d1d875
   MetaTextureTower *paint_tower;
d1d875
+  MetaTextureTower *paint_tower_right;
d1d875
 
d1d875
   CoglTexture *texture;
d1d875
+  CoglTexture *texture_right;
d1d875
   CoglTexture *mask_texture;
e47e58
   CoglSnippet *snippet;
d1d875
 
e47e58
@@ -129,8 +131,10 @@ meta_shaped_texture_init (MetaShapedTexture *self)
d1d875
   priv = self->priv = META_SHAPED_TEXTURE_GET_PRIVATE (self);
d1d875
 
d1d875
   priv->paint_tower = meta_texture_tower_new ();
d1d875
+  priv->paint_tower_right = NULL; /* demand create */
d1d875
 
d1d875
   priv->texture = NULL;
d1d875
+  priv->texture_right = NULL;
d1d875
   priv->mask_texture = NULL;
d1d875
   priv->create_mipmaps = TRUE;
e47e58
   priv->is_y_inverted = TRUE;
e47e58
@@ -191,11 +195,11 @@ meta_shaped_texture_dispose (GObject *object)
d1d875
   MetaShapedTexture *self = (MetaShapedTexture *) object;
d1d875
   MetaShapedTexturePrivate *priv = self->priv;
d1d875
 
d1d875
-  if (priv->paint_tower)
d1d875
-    meta_texture_tower_free (priv->paint_tower);
d1d875
-  priv->paint_tower = NULL;
d1d875
+  g_clear_pointer (&priv->paint_tower, meta_texture_tower_free);
d1d875
+  g_clear_pointer (&priv->paint_tower_right, meta_texture_tower_free);
d1d875
 
d1d875
   g_clear_pointer (&priv->texture, cogl_object_unref);
d1d875
+  g_clear_pointer (&priv->texture_right, cogl_object_unref);
d1d875
   g_clear_pointer (&priv->opaque_region, cairo_region_destroy);
d1d875
 
d1d875
   meta_shaped_texture_set_mask_texture (self, NULL);
e47e58
@@ -326,8 +330,9 @@ paint_clipped_rectangle (CoglFramebuffer       *fb,
d1d875
 }
d1d875
 
d1d875
 static void
d1d875
-set_cogl_texture (MetaShapedTexture *stex,
d1d875
-                  CoglTexture       *cogl_tex)
d1d875
+set_cogl_textures (MetaShapedTexture *stex,
d1d875
+                   CoglTexture       *cogl_tex,
d1d875
+                   CoglTexture       *cogl_tex_right)
d1d875
 {
d1d875
   MetaShapedTexturePrivate *priv;
d1d875
   guint width, height;
e47e58
@@ -338,8 +343,11 @@ set_cogl_texture (MetaShapedTexture *stex,
d1d875
 
d1d875
   if (priv->texture)
d1d875
     cogl_object_unref (priv->texture);
d1d875
+  if (priv->texture_right)
d1d875
+    cogl_object_unref (priv->texture_right);
d1d875
 
d1d875
   priv->texture = cogl_tex;
d1d875
+  priv->texture_right = cogl_tex_right;
d1d875
 
d1d875
   if (cogl_tex != NULL)
d1d875
     {
e47e58
@@ -353,6 +361,9 @@ set_cogl_texture (MetaShapedTexture *stex,
d1d875
       height = 0;
d1d875
     }
d1d875
 
d1d875
+  if (cogl_tex_right != NULL)
d1d875
+    cogl_object_ref (cogl_tex_right);
d1d875
+
d1d875
   if (priv->tex_width != width ||
d1d875
       priv->tex_height != height)
d1d875
     {
e47e58
@@ -368,52 +379,41 @@ set_cogl_texture (MetaShapedTexture *stex,
d1d875
    * previous buffer. We only queue a redraw in response to surface
d1d875
    * damage. */
d1d875
 
d1d875
+  if (cogl_tex_right != NULL)
d1d875
+    {
d1d875
+      if (priv->paint_tower_right == NULL)
d1d875
+        priv->paint_tower_right = meta_texture_tower_new ();
d1d875
+    }
d1d875
+  else
d1d875
+    {
d1d875
+      g_clear_pointer (&priv->paint_tower_right, meta_texture_tower_free);
d1d875
+    }
d1d875
+
d1d875
   if (priv->create_mipmaps)
d1d875
-    meta_texture_tower_set_base_texture (priv->paint_tower, cogl_tex);
d1d875
+    {
d1d875
+      meta_texture_tower_set_base_texture (priv->paint_tower, cogl_tex);
d1d875
+
d1d875
+      if (priv->paint_tower_right)
d1d875
+        meta_texture_tower_set_base_texture (priv->paint_tower_right, cogl_tex_right);
d1d875
+    }
d1d875
 }
d1d875
 
d1d875
 static void
d1d875
-meta_shaped_texture_paint (ClutterActor *actor)
d1d875
+paint_texture (MetaShapedTexture *stex,
d1d875
+               CoglTexture       *paint_tex)
d1d875
 {
d1d875
-  MetaShapedTexture *stex = (MetaShapedTexture *) actor;
d1d875
+  ClutterActor *actor = CLUTTER_ACTOR (stex);
d1d875
   MetaShapedTexturePrivate *priv = stex->priv;
d1d875
   guint tex_width, tex_height;
d1d875
   guchar opacity;
d1d875
   CoglContext *ctx;
d1d875
   CoglFramebuffer *fb;
d1d875
-  CoglTexture *paint_tex;
d1d875
   ClutterActorBox alloc;
d1d875
   CoglPipelineFilter filter;
d1d875
 
d1d875
   if (priv->clip_region && cairo_region_is_empty (priv->clip_region))
d1d875
     return;
d1d875
 
d1d875
-  if (!CLUTTER_ACTOR_IS_REALIZED (CLUTTER_ACTOR (stex)))
d1d875
-    clutter_actor_realize (CLUTTER_ACTOR (stex));
d1d875
-
d1d875
-  /* The GL EXT_texture_from_pixmap extension does allow for it to be
d1d875
-   * used together with SGIS_generate_mipmap, however this is very
d1d875
-   * rarely supported. Also, even when it is supported there
d1d875
-   * are distinct performance implications from:
d1d875
-   *
d1d875
-   *  - Updating mipmaps that we don't need
d1d875
-   *  - Having to reallocate pixmaps on the server into larger buffers
d1d875
-   *
d1d875
-   * So, we just unconditionally use our mipmap emulation code. If we
d1d875
-   * wanted to use SGIS_generate_mipmap, we'd have to  query COGL to
d1d875
-   * see if it was supported (no API currently), and then if and only
d1d875
-   * if that was the case, set the clutter texture quality to HIGH.
d1d875
-   * Setting the texture quality to high without SGIS_generate_mipmap
d1d875
-   * support for TFP textures will result in fallbacks to XGetImage.
d1d875
-   */
d1d875
-  if (priv->create_mipmaps)
d1d875
-    paint_tex = meta_texture_tower_get_paint_texture (priv->paint_tower);
d1d875
-  else
d1d875
-    paint_tex = COGL_TEXTURE (priv->texture);
d1d875
-
d1d875
-  if (paint_tex == NULL)
d1d875
-    return;
d1d875
-
d1d875
   tex_width = priv->tex_width;
d1d875
   tex_height = priv->tex_height;
d1d875
 
e47e58
@@ -574,6 +574,76 @@ meta_shaped_texture_paint (ClutterActor *actor)
d1d875
 }
d1d875
 
d1d875
 static void
d1d875
+meta_shaped_texture_paint (ClutterActor *actor)
d1d875
+{
d1d875
+  MetaShapedTexture *stex = (MetaShapedTexture *) actor;
d1d875
+  MetaShapedTexturePrivate *priv = stex->priv;
d1d875
+  CoglFramebuffer *fb;
d1d875
+  gboolean stereo;
d1d875
+  CoglTexture *paint_tex;
d1d875
+  CoglTexture *paint_tex_right;
d1d875
+
d1d875
+  if (priv->clip_region && cairo_region_is_empty (priv->clip_region))
d1d875
+    return;
d1d875
+
d1d875
+  if (!CLUTTER_ACTOR_IS_REALIZED (CLUTTER_ACTOR (stex)))
d1d875
+    clutter_actor_realize (CLUTTER_ACTOR (stex));
d1d875
+
d1d875
+  /* The GL EXT_texture_from_pixmap extension does allow for it to be
d1d875
+   * used together with SGIS_generate_mipmap, however this is very
d1d875
+   * rarely supported. Also, even when it is supported there
d1d875
+   * are distinct performance implications from:
d1d875
+   *
d1d875
+   *  - Updating mipmaps that we don't need
d1d875
+   *  - Having to reallocate pixmaps on the server into larger buffers
d1d875
+   *
d1d875
+   * So, we just unconditionally use our mipmap emulation code. If we
d1d875
+   * wanted to use SGIS_generate_mipmap, we'd have to  query COGL to
d1d875
+   * see if it was supported (no API currently), and then if and only
d1d875
+   * if that was the case, set the clutter texture quality to HIGH.
d1d875
+   * Setting the texture quality to high without SGIS_generate_mipmap
d1d875
+   * support for TFP textures will result in fallbacks to XGetImage.
d1d875
+   */
d1d875
+  if (priv->create_mipmaps)
d1d875
+    paint_tex = meta_texture_tower_get_paint_texture (priv->paint_tower);
d1d875
+  else
d1d875
+    paint_tex = COGL_TEXTURE (priv->texture);
d1d875
+
d1d875
+  if (paint_tex == NULL)
d1d875
+    return;
d1d875
+
d1d875
+  fb = cogl_get_draw_framebuffer ();
d1d875
+
d1d875
+  stereo = priv->texture_right && cogl_framebuffer_get_is_stereo (fb);
d1d875
+
d1d875
+  if (stereo)
d1d875
+    {
d1d875
+      if (priv->create_mipmaps)
d1d875
+	paint_tex_right = meta_texture_tower_get_paint_texture (priv->paint_tower_right);
d1d875
+      else
d1d875
+	paint_tex_right = COGL_TEXTURE (priv->texture_right);
d1d875
+    }
d1d875
+  else
d1d875
+    paint_tex_right = NULL;
d1d875
+
d1d875
+  if (paint_tex != NULL)
d1d875
+    {
d1d875
+      if (stereo)
d1d875
+	cogl_framebuffer_set_stereo_mode (fb, COGL_STEREO_LEFT);
d1d875
+      paint_texture (stex, paint_tex);
d1d875
+      if (stereo)
d1d875
+	cogl_framebuffer_set_stereo_mode (fb, COGL_STEREO_BOTH);
d1d875
+    }
d1d875
+
d1d875
+  if (paint_tex_right != NULL)
d1d875
+    {
d1d875
+      cogl_framebuffer_set_stereo_mode (fb, COGL_STEREO_RIGHT);
d1d875
+      paint_texture (stex, paint_tex_right);
d1d875
+      cogl_framebuffer_set_stereo_mode (fb, COGL_STEREO_BOTH);
d1d875
+    }
d1d875
+}
d1d875
+
d1d875
+static void
d1d875
 meta_shaped_texture_get_preferred_width (ClutterActor *self,
d1d875
                                          gfloat        for_height,
d1d875
                                          gfloat       *min_width_p,
e47e58
@@ -692,6 +762,12 @@ meta_shaped_texture_set_create_mipmaps (MetaShapedTexture *stex,
d1d875
       priv->create_mipmaps = create_mipmaps;
d1d875
       base_texture = create_mipmaps ? priv->texture : NULL;
d1d875
       meta_texture_tower_set_base_texture (priv->paint_tower, base_texture);
d1d875
+
d1d875
+      if (priv->paint_tower_right)
d1d875
+        {
d1d875
+          base_texture = create_mipmaps ? priv->texture_right : NULL;
d1d875
+          meta_texture_tower_set_base_texture (priv->paint_tower_right, base_texture);
d1d875
+        }
d1d875
     }
d1d875
 }
d1d875
 
e47e58
@@ -757,6 +833,8 @@ meta_shaped_texture_update_area (MetaShapedTexture *stex,
d1d875
     return FALSE;
d1d875
 
d1d875
   meta_texture_tower_update_area (priv->paint_tower, x, y, width, height);
d1d875
+  if (priv->paint_tower_right)
d1d875
+    meta_texture_tower_update_area (priv->paint_tower_right, x, y, width, height);
d1d875
 
d1d875
   unobscured_region = effective_unobscured_region (stex);
d1d875
   if (unobscured_region)
e47e58
@@ -789,17 +867,18 @@ meta_shaped_texture_update_area (MetaShapedTexture *stex,
d1d875
 }
d1d875
 
d1d875
 /**
d1d875
- * meta_shaped_texture_set_texture:
d1d875
+ * meta_shaped_texture_set_textures:
d1d875
  * @stex: The #MetaShapedTexture
d1d875
  * @pixmap: The #CoglTexture to display
d1d875
  */
d1d875
 void
d1d875
-meta_shaped_texture_set_texture (MetaShapedTexture *stex,
d1d875
-                                 CoglTexture       *texture)
d1d875
+meta_shaped_texture_set_textures (MetaShapedTexture *stex,
d1d875
+                                  CoglTexture       *texture,
d1d875
+                                  CoglTexture       *texture_right)
d1d875
 {
d1d875
   g_return_if_fail (META_IS_SHAPED_TEXTURE (stex));
d1d875
 
d1d875
-  set_cogl_texture (stex, texture);
d1d875
+  set_cogl_textures (stex, texture, texture_right);
d1d875
 }
d1d875
 
d1d875
 /**
d1d875
diff --git a/src/compositor/meta-surface-actor-wayland.c b/src/compositor/meta-surface-actor-wayland.c
e47e58
index 551322573..6ca68eb64 100644
d1d875
--- a/src/compositor/meta-surface-actor-wayland.c
d1d875
+++ b/src/compositor/meta-surface-actor-wayland.c
e47e58
@@ -403,7 +403,7 @@ meta_surface_actor_wayland_dispose (GObject *object)
e47e58
   MetaShapedTexture *stex =
e47e58
     meta_surface_actor_get_texture (META_SURFACE_ACTOR (self));
e47e58
 
e47e58
-  meta_shaped_texture_set_texture (stex, NULL);
e47e58
+  meta_shaped_texture_set_textures (stex, NULL, NULL);
e47e58
   if (priv->surface)
e47e58
     {
e47e58
       g_object_remove_weak_pointer (G_OBJECT (priv->surface),
e47e58
@@ -462,6 +462,14 @@ meta_surface_actor_wayland_new (MetaWaylandSurface *surface)
e47e58
   return META_SURFACE_ACTOR (self);
d1d875
 }
d1d875
 
e47e58
+void
e47e58
+meta_surface_actor_wayland_set_texture (MetaSurfaceActorWayland *self,
e47e58
+                                        CoglTexture *texture)
e47e58
+{
e47e58
+  MetaShapedTexture *stex = meta_surface_actor_get_texture (META_SURFACE_ACTOR (self));
e47e58
+  meta_shaped_texture_set_textures (stex, texture, NULL);
e47e58
+}
e47e58
+
d1d875
 MetaWaylandSurface *
e47e58
 meta_surface_actor_wayland_get_surface (MetaSurfaceActorWayland *self)
e47e58
 {
d1d875
diff --git a/src/compositor/meta-surface-actor-x11.c b/src/compositor/meta-surface-actor-x11.c
e47e58
index d32aeb68a..52db3808e 100644
d1d875
--- a/src/compositor/meta-surface-actor-x11.c
d1d875
+++ b/src/compositor/meta-surface-actor-x11.c
d1d875
@@ -31,6 +31,7 @@
67f8b7
 #include <cogl/winsys/cogl-texture-pixmap-x11.h>
d1d875
 
d1d875
 #include <meta/errors.h>
d1d875
+#include "compositor-private.h"
d1d875
 #include "window-private.h"
d1d875
 #include "meta-shaped-texture-private.h"
d1d875
 #include "meta-cullable.h"
67f8b7
@@ -43,6 +44,7 @@ struct _MetaSurfaceActorX11Private
67f8b7
   MetaDisplay *display;
67f8b7
 
67f8b7
   CoglTexture *texture;
67f8b7
+  CoglTexture *texture_right;
67f8b7
   Pixmap pixmap;
67f8b7
   Damage damage;
67f8b7
 
67f8b7
@@ -58,6 +60,8 @@ struct _MetaSurfaceActorX11Private
d1d875
   guint size_changed : 1;
d1d875
 
d1d875
   guint unredirected   : 1;
d1d875
+
d1d875
+  guint stereo : 1;
d1d875
 };
d1d875
 typedef struct _MetaSurfaceActorX11Private MetaSurfaceActorX11Private;
d1d875
 
67f8b7
@@ -94,7 +98,7 @@ detach_pixmap (MetaSurfaceActorX11 *self)
d1d875
    * you are supposed to be able to free a GLXPixmap after freeing the underlying
d1d875
    * pixmap, but it certainly doesn't work with current DRI/Mesa
d1d875
    */
d1d875
-  meta_shaped_texture_set_texture (stex, NULL);
d1d875
+  meta_shaped_texture_set_textures (stex, NULL, NULL);
d1d875
   cogl_flush ();
d1d875
 
d1d875
   meta_error_trap_push (display);
67f8b7
@@ -103,6 +107,7 @@ detach_pixmap (MetaSurfaceActorX11 *self)
67f8b7
   meta_error_trap_pop (display);
67f8b7
 
67f8b7
   g_clear_pointer (&priv->texture, cogl_object_unref);
67f8b7
+  g_clear_pointer (&priv->texture_right, cogl_object_unref);
67f8b7
 }
67f8b7
 
67f8b7
 static void
67f8b7
@@ -114,23 +119,35 @@ set_pixmap (MetaSurfaceActorX11 *self,
d1d875
   CoglContext *ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
d1d875
   MetaShapedTexture *stex = meta_surface_actor_get_texture (META_SURFACE_ACTOR (self));
d1d875
   CoglError *error = NULL;
d1d875
-  CoglTexture *texture;
d1d875
+  CoglTexturePixmapX11 *texture;
d1d875
+  CoglTexturePixmapX11 *texture_right;
d1d875
 
d1d875
   g_assert (priv->pixmap == None);
d1d875
   priv->pixmap = pixmap;
d1d875
 
d1d875
-  texture = COGL_TEXTURE (cogl_texture_pixmap_x11_new (ctx, priv->pixmap, FALSE, &error));
d1d875
+  if (priv->stereo)
d1d875
+    texture = cogl_texture_pixmap_x11_new_left (ctx, pixmap, FALSE, &error);
d1d875
+  else
d1d875
+    texture = cogl_texture_pixmap_x11_new (ctx, pixmap, FALSE, &error);
d1d875
+
d1d875
+  if (priv->stereo)
d1d875
+    texture_right = cogl_texture_pixmap_x11_new_right (texture);
d1d875
+  else
d1d875
+    texture_right = NULL;
d1d875
 
d1d875
   if (error != NULL)
d1d875
     {
d1d875
       g_warning ("Failed to allocate stex texture: %s", error->message);
d1d875
       cogl_error_free (error);
d1d875
     }
d1d875
-  else if (G_UNLIKELY (!cogl_texture_pixmap_x11_is_using_tfp_extension (COGL_TEXTURE_PIXMAP_X11 (texture))))
d1d875
+  else if (G_UNLIKELY (!cogl_texture_pixmap_x11_is_using_tfp_extension (texture)))
d1d875
     g_warning ("NOTE: Not using GLX TFP!\n");
d1d875
 
d1d875
-  priv->texture = texture;
d1d875
-  meta_shaped_texture_set_texture (stex, texture);
d1d875
+  priv->texture = COGL_TEXTURE (texture);
d1d875
+  if (priv->stereo)
67f8b7
+    priv->texture_right = COGL_TEXTURE (texture_right);
67f8b7
+
67f8b7
+  meta_shaped_texture_set_textures (stex, COGL_TEXTURE (texture), COGL_TEXTURE (texture_right));
d1d875
 }
d1d875
 
d1d875
 static void
67f8b7
@@ -433,8 +450,8 @@ reset_texture (MetaSurfaceActorX11 *self)
67f8b7
   /* Setting the texture to NULL will cause all the FBO's cached by the
67f8b7
    * shaped texture's MetaTextureTower to be discarded and recreated.
67f8b7
    */
67f8b7
-  meta_shaped_texture_set_texture (stex, NULL);
67f8b7
-  meta_shaped_texture_set_texture (stex, priv->texture);
67f8b7
+  meta_shaped_texture_set_textures (stex, NULL, NULL);
67f8b7
+  meta_shaped_texture_set_textures (stex, priv->texture, priv->texture_right);
67f8b7
 }
67f8b7
 
67f8b7
 MetaSurfaceActor *
67f8b7
@@ -443,12 +460,17 @@ meta_surface_actor_x11_new (MetaWindow *window)
d1d875
   MetaSurfaceActorX11 *self = g_object_new (META_TYPE_SURFACE_ACTOR_X11, NULL);
d1d875
   MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self);
d1d875
   MetaDisplay *display = meta_window_get_display (window);
d1d875
+  Window xwindow;
d1d875
 
d1d875
   g_assert (!meta_is_wayland_compositor ());
d1d875
 
d1d875
   priv->window = window;
d1d875
   priv->display = display;
d1d875
 
d1d875
+  xwindow = meta_window_x11_get_toplevel_xwindow (window);
d1d875
+  priv->stereo = meta_compositor_window_is_stereo (display->screen, xwindow);
d1d875
+  meta_compositor_select_stereo_notify (display->screen, xwindow);
d1d875
+
67f8b7
   g_signal_connect_object (priv->display, "gl-video-memory-purged",
67f8b7
                            G_CALLBACK (reset_texture), self, G_CONNECT_SWAPPED);
67f8b7
 
67f8b7
@@ -479,3 +501,21 @@ meta_surface_actor_x11_set_size (MetaSurfaceActorX11 *self,
d1d875
   priv->last_height = height;
d1d875
   meta_shaped_texture_set_fallback_size (stex, width, height);
d1d875
 }
d1d875
+
d1d875
+void
d1d875
+meta_surface_actor_x11_stereo_notify (MetaSurfaceActorX11 *self,
d1d875
+                                      gboolean             stereo_tree)
d1d875
+{
d1d875
+  MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self);
d1d875
+
d1d875
+  priv->stereo = stereo_tree != FALSE;
d1d875
+  detach_pixmap (self);
d1d875
+}
d1d875
+
d1d875
+gboolean
d1d875
+meta_surface_actor_x11_is_stereo (MetaSurfaceActorX11 *self)
d1d875
+{
d1d875
+  MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self);
d1d875
+
d1d875
+  return priv->stereo;
d1d875
+}
d1d875
diff --git a/src/compositor/meta-surface-actor-x11.h b/src/compositor/meta-surface-actor-x11.h
e47e58
index 0e692ee0f..4b2ecccb1 100644
d1d875
--- a/src/compositor/meta-surface-actor-x11.h
d1d875
+++ b/src/compositor/meta-surface-actor-x11.h
d1d875
@@ -64,6 +64,11 @@ MetaSurfaceActor * meta_surface_actor_x11_new (MetaWindow *window);
d1d875
 void meta_surface_actor_x11_set_size (MetaSurfaceActorX11 *self,
d1d875
                                       int width, int height);
d1d875
 
d1d875
+void meta_surface_actor_x11_stereo_notify (MetaSurfaceActorX11 *self,
d1d875
+                                           gboolean             stereo_tree);
d1d875
+
d1d875
+gboolean meta_surface_actor_x11_is_stereo (MetaSurfaceActorX11 *self);
d1d875
+
d1d875
 G_END_DECLS
d1d875
 
d1d875
 #endif /* __META_SURFACE_ACTOR_X11_H__ */
d1d875
diff --git a/src/compositor/meta-window-actor-private.h b/src/compositor/meta-window-actor-private.h
e47e58
index 72dcd1451..035d756b2 100644
d1d875
--- a/src/compositor/meta-window-actor-private.h
d1d875
+++ b/src/compositor/meta-window-actor-private.h
67f8b7
@@ -59,4 +59,9 @@ void meta_window_actor_effect_completed (MetaWindowActor  *actor,
d1d875
 MetaSurfaceActor *meta_window_actor_get_surface (MetaWindowActor *self);
d1d875
 void meta_window_actor_update_surface (MetaWindowActor *self);
d1d875
 
d1d875
+void meta_window_actor_stereo_notify (MetaWindowActor *actor,
d1d875
+                                      gboolean         stereo_tree);
d1d875
+
d1d875
+gboolean meta_window_actor_is_stereo (MetaWindowActor *actor);
d1d875
+
d1d875
 #endif /* META_WINDOW_ACTOR_PRIVATE_H */
d1d875
diff --git a/src/compositor/meta-window-actor.c b/src/compositor/meta-window-actor.c
e47e58
index 1184cd422..773e6d09d 100644
d1d875
--- a/src/compositor/meta-window-actor.c
d1d875
+++ b/src/compositor/meta-window-actor.c
e47e58
@@ -2150,3 +2150,25 @@ meta_window_actor_sync_updates_frozen (MetaWindowActor *self)
d1d875
 
d1d875
   meta_window_actor_set_updates_frozen (self, meta_window_updates_are_frozen (window));
d1d875
 }
d1d875
+
d1d875
+void
d1d875
+meta_window_actor_stereo_notify (MetaWindowActor *self,
d1d875
+                                 gboolean         stereo_tree)
d1d875
+{
d1d875
+  MetaWindowActorPrivate *priv = self->priv;
d1d875
+
d1d875
+  if (META_IS_SURFACE_ACTOR_X11 (priv->surface))
d1d875
+    meta_surface_actor_x11_stereo_notify (META_SURFACE_ACTOR_X11 (priv->surface),
d1d875
+                                          stereo_tree);
d1d875
+}
d1d875
+
d1d875
+gboolean
d1d875
+meta_window_actor_is_stereo (MetaWindowActor *self)
d1d875
+{
d1d875
+  MetaWindowActorPrivate *priv = self->priv;
d1d875
+
d1d875
+  if (META_IS_SURFACE_ACTOR_X11 (priv->surface))
d1d875
+    return meta_surface_actor_x11_is_stereo (META_SURFACE_ACTOR_X11 (priv->surface));
d1d875
+  else
d1d875
+    return FALSE;
d1d875
+}
d1d875
diff --git a/src/core/main.c b/src/core/main.c
e47e58
index dc1f1c4f6..2c1160711 100644
d1d875
--- a/src/core/main.c
d1d875
+++ b/src/core/main.c
67f8b7
@@ -47,6 +47,7 @@
67f8b7
 #include <meta/main.h>
67f8b7
 #include "util-private.h"
67f8b7
 #include "display-private.h"
67f8b7
+#include "stereo.h"
67f8b7
 #include <meta/errors.h>
67f8b7
 #include "ui.h"
67f8b7
 #include <meta/prefs.h>
e47e58
@@ -566,6 +567,9 @@ meta_init (void)
67f8b7
 
e47e58
   meta_init_backend (backend_gtype);
d1d875
 
d1d875
+  if (!meta_is_wayland_compositor ())
d1d875
+    meta_stereo_init ();
d1d875
+
d1d875
   meta_clutter_init ();
d1d875
 
d1d875
 #ifdef HAVE_WAYLAND
67f8b7
diff --git a/src/core/stereo.c b/src/core/stereo.c
67f8b7
new file mode 100644
e47e58
index 000000000..5a232b67c
67f8b7
--- /dev/null
67f8b7
+++ b/src/core/stereo.c
d1d875
@@ -0,0 +1,153 @@
d1d875
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
d1d875
+
d1d875
+/*
d1d875
+ * Copyright (C) 2014 Red Hat, Inc.
d1d875
+ *
d1d875
+ * This program is free software; you can redistribute it and/or
d1d875
+ * modify it under the terms of the GNU General Public License as
d1d875
+ * published by the Free Software Foundation; either version 2 of the
d1d875
+ * License, or (at your option) any later version.
d1d875
+ *
d1d875
+ * This program is distributed in the hope that it will be useful, but
d1d875
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
d1d875
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
d1d875
+ * General Public License for more details.
d1d875
+ *
d1d875
+ * You should have received a copy of the GNU General Public License
d1d875
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
d1d875
+ */
d1d875
+
d1d875
+/*
d1d875
+ * SECTION:stereo
d1d875
+ * @short_description: Keep track of whether we are a stereo compositor
d1d875
+ *
d1d875
+ * With GLX, we need to use a different GL context for stereo and
d1d875
+ * non-stereo support. Support for multiple GL contexts is unfinished
d1d875
+ * in Cogl and entirely lacking in Clutter, so it's by far easier
d1d875
+ * to just restart Mutter when we detect a stereo window.
d1d875
+ *
d1d875
+ * A property _MUTTER_ENABLE_STEREO is maintained on the root window
d1d875
+ * to know whether we should initialize clutter for stereo or not.
d1d875
+ * When the presence or absence of stereo windows mismatches the
d1d875
+ * stereo-enabled state for a sufficiently long period of time,
d1d875
+ * we restart Mutter.
d1d875
+ */
d1d875
+
d1d875
+#include <config.h>
d1d875
+
d1d875
+#include <clutter/x11/clutter-x11.h>
d1d875
+#include <gio/gunixinputstream.h>
d1d875
+#include <X11/Xatom.h>
d1d875
+
d1d875
+#include <meta/main.h>
d1d875
+#include "ui.h"
d1d875
+#include <meta/util.h>
d1d875
+#include "display-private.h"
d1d875
+#include "stereo.h"
d1d875
+#include "util-private.h"
d1d875
+
d1d875
+static guint stereo_switch_id = 0;
d1d875
+static gboolean stereo_enabled = FALSE;
d1d875
+/* -1 so the first time meta_stereo_set_have_stereo_windows() is called
d1d875
+ * we avoid the short-circuit and set up a timeout to restart
d1d875
+ * if necessary */
d1d875
+static gboolean stereo_have_windows = (gboolean)-1;
d1d875
+static gboolean stereo_restart = FALSE;
d1d875
+
d1d875
+#define STEREO_ENABLE_WAIT 1000
d1d875
+#define STEREO_DISABLE_WAIT 5000
d1d875
+
d1d875
+void
d1d875
+meta_stereo_init (void)
d1d875
+{
d1d875
+  Display *xdisplay;
d1d875
+  Window root;
d1d875
+  Atom atom_enable_stereo;
d1d875
+  Atom type;
d1d875
+  int format;
d1d875
+  unsigned long n_items, bytes_after;
d1d875
+  guchar *data;
d1d875
+
d1d875
+  xdisplay = XOpenDisplay (NULL);
d1d875
+  if (xdisplay == NULL)
d1d875
+    meta_fatal ("Unable to open X display %s\n", XDisplayName (NULL));
d1d875
+
d1d875
+  root = DefaultRootWindow (xdisplay);
d1d875
+  atom_enable_stereo = XInternAtom (xdisplay, "_MUTTER_ENABLE_STEREO", False);
d1d875
+
d1d875
+  XGetWindowProperty (xdisplay, root, atom_enable_stereo,
d1d875
+                      0, 1, False, XA_INTEGER,
d1d875
+                      &type, &format, &n_items, &bytes_after, &data);
d1d875
+  if (type == XA_INTEGER)
d1d875
+    {
d1d875
+      if (format == 32 && n_items == 1 && bytes_after == 0)
d1d875
+        {
d1d875
+          stereo_enabled = *(long *)data;
d1d875
+        }
d1d875
+      else
d1d875
+        {
d1d875
+          meta_warning ("Bad value for _MUTTER_ENABLE_STEREO property\n");
d1d875
+        }
d1d875
+
d1d875
+      XFree (data);
d1d875
+    }
d1d875
+  else if (type != None)
d1d875
+    {
d1d875
+      meta_warning ("Bad type for _MUTTER_ENABLE_STEREO property\n");
d1d875
+    }
d1d875
+
d1d875
+  meta_verbose ("On startup, _MUTTER_ENABLE_STEREO=%s",
d1d875
+                stereo_enabled ? "yes" : "no");
d1d875
+  clutter_x11_set_use_stereo_stage (stereo_enabled);
d1d875
+  XCloseDisplay (xdisplay);
d1d875
+}
d1d875
+
d1d875
+static gboolean
d1d875
+meta_stereo_switch (gpointer data)
d1d875
+{
d1d875
+  stereo_switch_id = 0;
d1d875
+  stereo_restart = TRUE;
d1d875
+
d1d875
+  meta_restart (stereo_have_windows ?
d1d875
+                _("Enabling stereo...") :
d1d875
+                _("Disabling stereo..."));
d1d875
+
d1d875
+  return FALSE;
d1d875
+}
d1d875
+
d1d875
+void
d1d875
+meta_stereo_set_have_stereo_windows (gboolean have_windows)
d1d875
+{
d1d875
+  have_windows = have_windows != FALSE;
d1d875
+
d1d875
+  if (!stereo_restart && have_windows != stereo_have_windows)
d1d875
+    {
d1d875
+      MetaDisplay *display = meta_get_display ();
d1d875
+      Display *xdisplay = meta_display_get_xdisplay (display);
d1d875
+      Window root = DefaultRootWindow (xdisplay);
d1d875
+      Atom atom_enable_stereo = XInternAtom (xdisplay, "_MUTTER_ENABLE_STEREO", False);
d1d875
+      long value;
d1d875
+
d1d875
+      stereo_have_windows = have_windows;
d1d875
+
d1d875
+      if (stereo_have_windows)
d1d875
+        meta_verbose ("Detected stereo windows\n");
d1d875
+      else
d1d875
+        meta_verbose ("No stereo windows detected\n");
d1d875
+
d1d875
+      value = stereo_have_windows;
d1d875
+      XChangeProperty (xdisplay, root,
d1d875
+                       atom_enable_stereo, XA_INTEGER, 32,
d1d875
+                       PropModeReplace, (guchar *)&value, 1);
d1d875
+
d1d875
+      if (stereo_switch_id != 0)
d1d875
+        {
d1d875
+          g_source_remove (stereo_switch_id);
d1d875
+          stereo_switch_id = 0;
d1d875
+        }
d1d875
+
d1d875
+      if (stereo_have_windows != stereo_enabled)
d1d875
+        stereo_switch_id = g_timeout_add (stereo_have_windows ? STEREO_ENABLE_WAIT : STEREO_DISABLE_WAIT,
d1d875
+                                          meta_stereo_switch, NULL);
d1d875
+    }
d1d875
+}
d1d875
diff --git a/src/core/stereo.h b/src/core/stereo.h
d1d875
new file mode 100644
e47e58
index 000000000..ccd1d702a
d1d875
--- /dev/null
d1d875
+++ b/src/core/stereo.h
d1d875
@@ -0,0 +1,28 @@
d1d875
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
d1d875
+
d1d875
+/*
d1d875
+ * Copyright (C) 2014 Red Hat, Inc.
d1d875
+ *
d1d875
+ * This program is free software; you can redistribute it and/or
d1d875
+ * modify it under the terms of the GNU General Public License as
d1d875
+ * published by the Free Software Foundation; either version 2 of the
d1d875
+ * License, or (at your option) any later version.
d1d875
+ *
d1d875
+ * This program is distributed in the hope that it will be useful, but
d1d875
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
d1d875
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
d1d875
+ * General Public License for more details.
d1d875
+ *
d1d875
+ * You should have received a copy of the GNU General Public License
d1d875
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
d1d875
+ */
d1d875
+
d1d875
+#ifndef META_STEREO_H
d1d875
+#define META_STEREO_H
d1d875
+
d1d875
+void     meta_stereo_init                    (void);
d1d875
+void     meta_stereo_set_have_stereo_windows (gboolean have_windows);
d1d875
+gboolean meta_stereo_is_restart              (void);
d1d875
+void     meta_stereo_finish_restart          (void);
d1d875
+
d1d875
+#endif
e47e58
diff --git a/src/wayland/meta-wayland-surface.c b/src/wayland/meta-wayland-surface.c
e47e58
index 6f9df37da..d353ae5d0 100644
e47e58
--- a/src/wayland/meta-wayland-surface.c
e47e58
+++ b/src/wayland/meta-wayland-surface.c
e47e58
@@ -789,7 +789,7 @@ apply_pending_state (MetaWaylandSurface      *surface,
e47e58
               snippet = meta_wayland_buffer_create_snippet (pending->buffer);
e47e58
               is_y_inverted = meta_wayland_buffer_is_y_inverted (pending->buffer);
e47e58
 
e47e58
-              meta_shaped_texture_set_texture (stex, texture);
e47e58
+              meta_shaped_texture_set_textures (stex, texture, NULL);
e47e58
               meta_shaped_texture_set_snippet (stex, snippet);
e47e58
               meta_shaped_texture_set_is_y_inverted (stex, is_y_inverted);
e47e58
               g_clear_pointer (&snippet, cogl_object_unref);
d1d875
-- 
e47e58
2.14.2
d1d875