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

68333f
From 9ceccaf38295d73b729bc3a6777fa6b948fa4007 Mon Sep 17 00:00:00 2001
68333f
From: "Owen W. Taylor" <otaylor@fishsoup.net>
68333f
Date: Thu, 8 May 2014 18:44:15 -0400
68333f
Subject: [PATCH] Add support for quad-buffer stereo
68333f
68333f
Track the stereo status of windows using the new EXT_stereo_tree
68333f
GLX extension.
68333f
68333f
When stereo is enabled or disabled, a restart is triggered via
68333f
meta_restart() after a timeout, setting a _META_ENABLE_STEREO
68333f
property on the root window to indicate whether we should
68333f
turn on a stereo stage for clutter. The property avoids a loop,
68333f
since we need to enable stereo *before* initializing Clutter and GL,
68333f
but we need GL to figure out whether we have stereo windows.
68333f
68333f
Stereo windows are drawn to the stage using new functionality
68333f
in Cogl to setup a stereo context, select which buffer to draw
68333f
to, and draw either the left or right buffer of a stereo
68333f
texture_from_pixmap.
68333f
---
68333f
 src/Makefile.am                              |   2 +
68333f
 src/compositor/compositor-private.h          |  10 ++
68333f
 src/compositor/compositor.c                  | 127 +++++++++++++++++++-
68333f
 src/compositor/meta-shaped-texture-private.h |  37 ++++++
68333f
 src/compositor/meta-shaped-texture.c         | 166 ++++++++++++++++++++-------
68333f
 src/compositor/meta-window-actor-private.h   |   7 ++
68333f
 src/compositor/meta-window-actor.c           |  27 ++++-
68333f
 src/core/main.c                              |   2 +
68333f
 src/core/stereo.c                            | 144 +++++++++++++++++++++++
68333f
 src/core/stereo.h                            |  28 +++++
68333f
 src/meta/meta-shaped-texture.h               |   3 +-
68333f
 11 files changed, 508 insertions(+), 45 deletions(-)
68333f
 create mode 100644 src/compositor/meta-shaped-texture-private.h
68333f
 create mode 100644 src/core/stereo.c
68333f
 create mode 100644 src/core/stereo.h
68333f
68333f
diff --git a/src/Makefile.am b/src/Makefile.am
68333f
index d664b54..1d2422e 100644
68333f
--- a/src/Makefile.am
68333f
+++ b/src/Makefile.am
68333f
@@ -122,6 +122,8 @@ libmutter_la_SOURCES =				\
68333f
 	core/restart.c				\
68333f
 	core/session.c				\
68333f
 	core/session.h				\
68333f
+	core/stereo.c				\
68333f
+	core/stereo.h				\
68333f
 	core/stack.c				\
68333f
 	core/stack.h				\
68333f
 	core/stack-tracker.c			\
68333f
diff --git a/src/compositor/compositor-private.h b/src/compositor/compositor-private.h
68333f
index acb8d3c..b4c5c16 100644
68333f
--- a/src/compositor/compositor-private.h
68333f
+++ b/src/compositor/compositor-private.h
68333f
@@ -28,6 +28,8 @@ struct _MetaCompositor
68333f
   gint64          server_time_query_time;
68333f
   gint64          server_time_offset;
68333f
 
68333f
+  int             glx_opcode;
68333f
+
68333f
   guint           server_time_is_monotonic_time : 1;
68333f
   guint           show_redraw : 1;
68333f
   guint           debug       : 1;
68333f
@@ -56,6 +58,9 @@ struct _MetaCompScreen
68333f
 
68333f
   gint                   switch_workspace_in_progress;
68333f
 
68333f
+  guint                  stereo_tree_ext : 1;
68333f
+  guint                  have_stereo_windows : 1;
68333f
+
68333f
   MetaPluginManager *plugin_mgr;
68333f
 };
68333f
 
68333f
@@ -79,4 +84,9 @@ gint64 meta_compositor_monotonic_time_to_server_time (MetaDisplay *display,
68333f
 
68333f
 void meta_check_end_modal (MetaScreen *screen);
68333f
 
68333f
+gboolean meta_compositor_window_is_stereo     (MetaScreen *screen,
68333f
+                                               Window      xwindow);
68333f
+void     meta_compositor_select_stereo_notify (MetaScreen *screen,
68333f
+                                               Window      xwindow);
68333f
+
68333f
 #endif /* META_COMPOSITOR_PRIVATE_H */
68333f
diff --git a/src/compositor/compositor.c b/src/compositor/compositor.c
68333f
index 539a7a6..fd29e48 100644
68333f
--- a/src/compositor/compositor.c
68333f
+++ b/src/compositor/compositor.c
68333f
@@ -86,7 +86,8 @@
68333f
 #include "meta-window-group.h"
68333f
 #include "window-private.h" /* to check window->hidden */
68333f
 #include "display-private.h" /* for meta_display_lookup_x_window() */
68333f
-#include "util-private.h"
68333f
+#include "stack-tracker.h"
68333f
+#include "stereo.h"
68333f
 #include <X11/extensions/shape.h>
68333f
 #include <X11/extensions/Xcomposite.h>
68333f
 
68333f
@@ -579,6 +580,101 @@ redirect_windows (MetaCompositor *compositor,
68333f
     }
68333f
 }
68333f
 
68333f
+#define GLX_STEREO_TREE_EXT        0x20F5
68333f
+#define GLX_STEREO_NOTIFY_MASK_EXT 0x00000001
68333f
+#define GLX_STEREO_NOTIFY_EXT      0x00000000
68333f
+
68333f
+typedef struct {
68333f
+  int type;
68333f
+  unsigned long serial;
68333f
+  Bool send_event;
68333f
+  Display *display;
68333f
+  int extension;
68333f
+  int evtype;
68333f
+  Drawable window;
68333f
+  Bool stereo_tree;
68333f
+} StereoNotifyEvent;
68333f
+
68333f
+static gboolean
68333f
+screen_has_stereo_tree_ext (MetaScreen *screen)
68333f
+{
68333f
+#if 0
68333f
+  MetaDisplay *display = meta_screen_get_display (screen);
68333f
+  Display     *xdisplay = meta_display_get_xdisplay (display);
68333f
+  const char *extensions_string;
68333f
+
68333f
+  static const char * (*query_extensions_string) (Display *display,
68333f
+                                                  int      screen);
68333f
+
68333f
+  if (query_extensions_string == NULL)
68333f
+    query_extensions_string =
68333f
+      (const char * (*) (Display *, int))
68333f
+      cogl_get_proc_address ("glXQueryExtensionsString");
68333f
+
68333f
+  extensions_string = query_extensions_string (xdisplay,
68333f
+                                               meta_screen_get_screen_number (screen));
68333f
+
68333f
+  return strstr (extensions_string, "EXT_stereo_tree") != 0;
68333f
+#else
68333f
+  return TRUE;
68333f
+#endif
68333f
+}
68333f
+
68333f
+#include <GL/gl.h>
68333f
+
68333f
+gboolean
68333f
+meta_compositor_window_is_stereo (MetaScreen *screen,
68333f
+                                  Window      xwindow)
68333f
+{
68333f
+  MetaCompScreen *info = meta_screen_get_compositor_data (screen);
68333f
+  MetaDisplay    *display = meta_screen_get_display (screen);
68333f
+  Display        *xdisplay = meta_display_get_xdisplay (display);
68333f
+
68333f
+  static int (*query_drawable) (Display      *dpy,
68333f
+                                Drawable      draw,
68333f
+                                int           attribute,
68333f
+                                unsigned int *value);
68333f
+
68333f
+  if (info->stereo_tree_ext)
68333f
+    {
68333f
+      unsigned int stereo_tree = 0;
68333f
+
68333f
+      if (query_drawable == NULL)
68333f
+        query_drawable =
68333f
+          (int (*) (Display *, Drawable, int, unsigned int *))
68333f
+          cogl_get_proc_address ("glXQueryDrawable");
68333f
+
68333f
+      query_drawable (xdisplay, xwindow, GLX_STEREO_TREE_EXT, &stereo_tree);
68333f
+
68333f
+      return stereo_tree != 0;
68333f
+    }
68333f
+  else
68333f
+    return FALSE;
68333f
+}
68333f
+
68333f
+void
68333f
+meta_compositor_select_stereo_notify (MetaScreen *screen,
68333f
+                                      Window      xwindow)
68333f
+{
68333f
+  MetaCompScreen *info = meta_screen_get_compositor_data (screen);
68333f
+  MetaDisplay    *display = meta_screen_get_display (screen);
68333f
+  Display        *xdisplay = meta_display_get_xdisplay (display);
68333f
+
68333f
+  static void (*select_event) (Display      *dpy,
68333f
+                               Drawable      draw,
68333f
+                               unsigned long event_mask);
68333f
+
68333f
+  if (info->stereo_tree_ext)
68333f
+    {
68333f
+      if (select_event == NULL)
68333f
+        select_event =
68333f
+          (void (*) (Display *, Drawable, unsigned long))
68333f
+          cogl_get_proc_address ("glXSelectEvent");
68333f
+
68333f
+      select_event (xdisplay, xwindow, GLX_STEREO_NOTIFY_MASK_EXT);
68333f
+    }
68333f
+}
68333f
+
68333f
 void
68333f
 meta_compositor_manage_screen (MetaCompositor *compositor,
68333f
                                MetaScreen     *screen)
68333f
@@ -609,6 +705,8 @@ meta_compositor_manage_screen (MetaCompositor *compositor,
68333f
   info->output = None;
68333f
   info->windows = NULL;
68333f
 
68333f
+  info->stereo_tree_ext = screen_has_stereo_tree_ext (screen);
68333f
+
68333f
   meta_screen_set_cm_selection (screen);
68333f
 
68333f
   info->stage = clutter_stage_new ();
68333f
@@ -995,6 +1093,23 @@ meta_compositor_process_event (MetaCompositor *compositor,
68333f
 	  DEBUG_TRACE ("meta_compositor_process_event (process_damage)\n");
68333f
           process_damage (compositor, (XDamageNotifyEvent *) event, window);
68333f
         }
68333f
+      else if (event->type == GenericEvent &&
68333f
+               event->xcookie.extension == compositor->glx_opcode)
68333f
+        {
68333f
+          if (event->xcookie.evtype == GLX_STEREO_NOTIFY_EXT)
68333f
+            {
68333f
+              StereoNotifyEvent *stereo_event = (StereoNotifyEvent *)(event->xcookie.data);
68333f
+              window = meta_display_lookup_x_window (compositor->display, stereo_event->window);
68333f
+
68333f
+              if (window != NULL)
68333f
+                {
68333f
+                  MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
68333f
+                  meta_window_actor_stereo_notify (window_actor, stereo_event->stereo_tree);
68333f
+                  meta_stack_tracker_queue_sync_stack (window->screen->stack_tracker);
68333f
+                }
68333f
+            }
68333f
+        }
68333f
+
68333f
       break;
68333f
     }
68333f
 
68333f
@@ -1209,6 +1324,7 @@ meta_compositor_sync_stack (MetaCompositor  *compositor,
68333f
 {
68333f
   GList *old_stack;
68333f
   MetaCompScreen *info = meta_screen_get_compositor_data (screen);
68333f
+  int stereo_window_count = 0;
68333f
 
68333f
   DEBUG_TRACE ("meta_compositor_sync_stack\n");
68333f
 
68333f
@@ -1286,12 +1402,16 @@ meta_compositor_sync_stack (MetaCompositor  *compositor,
68333f
        * near the front of the other.)
68333f
        */
68333f
       info->windows = g_list_prepend (info->windows, actor);
68333f
+      if (meta_window_actor_is_stereo (actor))
68333f
+        stereo_window_count++;
68333f
 
68333f
       stack = g_list_remove (stack, window);
68333f
       old_stack = g_list_remove (old_stack, actor);
68333f
     }
68333f
 
68333f
   sync_actor_stacking (info);
68333f
+
68333f
+  meta_stereo_set_have_stereo_windows (stereo_window_count > 0);
68333f
 }
68333f
 
68333f
 void
68333f
@@ -1505,6 +1625,7 @@ meta_compositor_new (MetaDisplay *display)
68333f
   Atom                   atoms[G_N_ELEMENTS(atom_names)];
68333f
   MetaCompositor        *compositor;
68333f
   Display               *xdisplay = meta_display_get_xdisplay (display);
68333f
+  int glx_major_opcode, glx_first_event, glx_first_error;
68333f
 
68333f
   if (!composite_at_least_version (display, 0, 3))
68333f
     return NULL;
68333f
@@ -1531,6 +1652,10 @@ meta_compositor_new (MetaDisplay *display)
68333f
   compositor->repaint_func_id = clutter_threads_add_repaint_func (meta_repaint_func,
68333f
                                                                   compositor,
68333f
                                                                   NULL);
68333f
+  if (XQueryExtension (xdisplay,
68333f
+                       "GLX",
68333f
+                       &glx_major_opcode, &glx_first_event, &glx_first_error))
68333f
+    compositor->glx_opcode = glx_major_opcode;
68333f
 
68333f
   return compositor;
68333f
 }
68333f
diff --git a/src/compositor/meta-shaped-texture-private.h b/src/compositor/meta-shaped-texture-private.h
68333f
new file mode 100644
68333f
index 0000000..c70f6a8
68333f
--- /dev/null
68333f
+++ b/src/compositor/meta-shaped-texture-private.h
68333f
@@ -0,0 +1,37 @@
68333f
+/*
68333f
+ * shaped texture
68333f
+ *
68333f
+ * An actor to draw a texture clipped to a list of rectangles
68333f
+ *
68333f
+ * Authored By Neil Roberts  <neil@linux.intel.com>
68333f
+ *
68333f
+ * Copyright (C) 2008 Intel Corporation
68333f
+ *               2013 Red Hat, Inc.
68333f
+ *
68333f
+ * This program is free software; you can redistribute it and/or
68333f
+ * modify it under the terms of the GNU General Public License as
68333f
+ * published by the Free Software Foundation; either version 2 of the
68333f
+ * License, or (at your option) any later version.
68333f
+ *
68333f
+ * This program is distributed in the hope that it will be useful, but
68333f
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
68333f
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
68333f
+ * General Public License for more details.
68333f
+ *
68333f
+ * You should have received a copy of the GNU General Public License
68333f
+ * along with this program; if not, write to the Free Software
68333f
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
68333f
+ * 02111-1307, USA.
68333f
+ */
68333f
+
68333f
+#ifndef __META_SHAPED_TEXTURE_PRIVATE_H__
68333f
+#define __META_SHAPED_TEXTURE_PRIVATE_H__
68333f
+
68333f
+#include <meta/meta-shaped-texture.h>
68333f
+
68333f
+ClutterActor *meta_shaped_texture_new (void);
68333f
+gboolean meta_shaped_texture_get_unobscured_bounds (MetaShapedTexture     *stex,
68333f
+                                                    cairo_rectangle_int_t *unobscured_bounds);
68333f
+gboolean meta_shaped_texture_is_obscured (MetaShapedTexture *self);
68333f
+
68333f
+#endif
68333f
diff --git a/src/compositor/meta-shaped-texture.c b/src/compositor/meta-shaped-texture.c
68333f
index c6239c9..132cb09 100644
68333f
--- a/src/compositor/meta-shaped-texture.c
68333f
+++ b/src/compositor/meta-shaped-texture.c
68333f
@@ -65,8 +65,10 @@ G_DEFINE_TYPE (MetaShapedTexture, meta_shaped_texture,
68333f
 struct _MetaShapedTexturePrivate
68333f
 {
68333f
   MetaTextureTower *paint_tower;
68333f
+  MetaTextureTower *paint_tower_right;
68333f
   Pixmap pixmap;
68333f
   CoglTexturePixmapX11 *texture;
68333f
+  CoglTexturePixmapX11 *texture_right;
68333f
   CoglTexture *mask_texture;
68333f
   CoglPipeline *pipeline;
68333f
   CoglPipeline *pipeline_unshaped;
68333f
@@ -75,6 +77,7 @@ struct _MetaShapedTexturePrivate
68333f
 
68333f
   guint tex_width, tex_height;
68333f
 
68333f
+  guint stereo : 1;
68333f
   guint create_mipmaps : 1;
68333f
 };
68333f
 
68333f
@@ -103,7 +106,9 @@ meta_shaped_texture_init (MetaShapedTexture *self)
68333f
   priv = self->priv = META_SHAPED_TEXTURE_GET_PRIVATE (self);
68333f
 
68333f
   priv->paint_tower = meta_texture_tower_new ();
68333f
+  priv->paint_tower_right = NULL; /* demand create */
68333f
   priv->texture = NULL;
68333f
+  priv->texture_right = NULL;
68333f
   priv->mask_texture = NULL;
68333f
   priv->create_mipmaps = TRUE;
68333f
 }
68333f
@@ -114,13 +119,13 @@ meta_shaped_texture_dispose (GObject *object)
68333f
   MetaShapedTexture *self = (MetaShapedTexture *) object;
68333f
   MetaShapedTexturePrivate *priv = self->priv;
68333f
 
68333f
-  if (priv->paint_tower)
68333f
-    meta_texture_tower_free (priv->paint_tower);
68333f
-  priv->paint_tower = NULL;
68333f
+  g_clear_pointer (&priv->paint_tower, meta_texture_tower_free);
68333f
+  g_clear_pointer (&priv->paint_tower_right, meta_texture_tower_free);
68333f
 
68333f
   g_clear_pointer (&priv->pipeline, cogl_object_unref);
68333f
   g_clear_pointer (&priv->pipeline_unshaped, cogl_object_unref);
68333f
   g_clear_pointer (&priv->texture, cogl_object_unref);
68333f
+  g_clear_pointer (&priv->texture_right, cogl_object_unref);
68333f
 
68333f
   meta_shaped_texture_set_mask_texture (self, NULL);
68333f
   meta_shaped_texture_set_clip_region (self, NULL);
68333f
@@ -129,11 +134,11 @@ meta_shaped_texture_dispose (GObject *object)
68333f
 }
68333f
 
68333f
 static void
68333f
-meta_shaped_texture_paint (ClutterActor *actor)
68333f
+paint_texture (MetaShapedTexture *stex,
68333f
+               CoglTexture       *paint_tex)
68333f
 {
68333f
-  MetaShapedTexture *stex = (MetaShapedTexture *) actor;
68333f
   MetaShapedTexturePrivate *priv = stex->priv;
68333f
-  CoglTexture *paint_tex;
68333f
+  ClutterActor *actor = CLUTTER_ACTOR (stex);
68333f
   guint tex_width, tex_height;
68333f
   ClutterActorBox alloc;
68333f
 
68333f
@@ -145,32 +150,6 @@ meta_shaped_texture_paint (ClutterActor *actor)
68333f
   if (priv->clip_region && cairo_region_is_empty (priv->clip_region))
68333f
     return;
68333f
 
68333f
-  if (!CLUTTER_ACTOR_IS_REALIZED (CLUTTER_ACTOR (stex)))
68333f
-    clutter_actor_realize (CLUTTER_ACTOR (stex));
68333f
-
68333f
-  /* The GL EXT_texture_from_pixmap extension does allow for it to be
68333f
-   * used together with SGIS_generate_mipmap, however this is very
68333f
-   * rarely supported. Also, even when it is supported there
68333f
-   * are distinct performance implications from:
68333f
-   *
68333f
-   *  - Updating mipmaps that we don't need
68333f
-   *  - Having to reallocate pixmaps on the server into larger buffers
68333f
-   *
68333f
-   * So, we just unconditionally use our mipmap emulation code. If we
68333f
-   * wanted to use SGIS_generate_mipmap, we'd have to  query COGL to
68333f
-   * see if it was supported (no API currently), and then if and only
68333f
-   * if that was the case, set the clutter texture quality to HIGH.
68333f
-   * Setting the texture quality to high without SGIS_generate_mipmap
68333f
-   * support for TFP textures will result in fallbacks to XGetImage.
68333f
-   */
68333f
-  if (priv->create_mipmaps)
68333f
-    paint_tex = meta_texture_tower_get_paint_texture (priv->paint_tower);
68333f
-  else
68333f
-    paint_tex = COGL_TEXTURE (priv->texture);
68333f
-
68333f
-  if (paint_tex == NULL)
68333f
-    return;
68333f
-
68333f
   tex_width = priv->tex_width;
68333f
   tex_height = priv->tex_height;
68333f
 
68333f
@@ -279,6 +258,76 @@ meta_shaped_texture_paint (ClutterActor *actor)
68333f
 }
68333f
 
68333f
 static void
68333f
+meta_shaped_texture_paint (ClutterActor *actor)
68333f
+{
68333f
+  MetaShapedTexture *stex = (MetaShapedTexture *) actor;
68333f
+  MetaShapedTexturePrivate *priv = stex->priv;
68333f
+  CoglFramebuffer *fb;
68333f
+  gboolean stereo;
68333f
+  CoglTexture *paint_tex;
68333f
+  CoglTexture *paint_tex_right;
68333f
+
68333f
+  if (priv->clip_region && cairo_region_is_empty (priv->clip_region))
68333f
+    return;
68333f
+
68333f
+  if (!CLUTTER_ACTOR_IS_REALIZED (CLUTTER_ACTOR (stex)))
68333f
+    clutter_actor_realize (CLUTTER_ACTOR (stex));
68333f
+
68333f
+  /* The GL EXT_texture_from_pixmap extension does allow for it to be
68333f
+   * used together with SGIS_generate_mipmap, however this is very
68333f
+   * rarely supported. Also, even when it is supported there
68333f
+   * are distinct performance implications from:
68333f
+   *
68333f
+   *  - Updating mipmaps that we don't need
68333f
+   *  - Having to reallocate pixmaps on the server into larger buffers
68333f
+   *
68333f
+   * So, we just unconditionally use our mipmap emulation code. If we
68333f
+   * wanted to use SGIS_generate_mipmap, we'd have to  query COGL to
68333f
+   * see if it was supported (no API currently), and then if and only
68333f
+   * if that was the case, set the clutter texture quality to HIGH.
68333f
+   * Setting the texture quality to high without SGIS_generate_mipmap
68333f
+   * support for TFP textures will result in fallbacks to XGetImage.
68333f
+   */
68333f
+  if (priv->create_mipmaps)
68333f
+    paint_tex = meta_texture_tower_get_paint_texture (priv->paint_tower);
68333f
+  else
68333f
+    paint_tex = COGL_TEXTURE (priv->texture);
68333f
+
68333f
+  if (paint_tex == NULL)
68333f
+    return;
68333f
+
68333f
+  fb = cogl_get_draw_framebuffer ();
68333f
+
68333f
+  stereo = priv->stereo && cogl_framebuffer_get_is_stereo (fb);
68333f
+
68333f
+  if (stereo)
68333f
+    {
68333f
+      if (priv->create_mipmaps)
68333f
+	paint_tex_right = meta_texture_tower_get_paint_texture (priv->paint_tower_right);
68333f
+      else
68333f
+	paint_tex_right = COGL_TEXTURE (priv->texture_right);
68333f
+    }
68333f
+  else
68333f
+    paint_tex_right = NULL;
68333f
+
68333f
+  if (paint_tex != NULL)
68333f
+    {
68333f
+      if (stereo)
68333f
+	cogl_framebuffer_set_stereo_mode (fb, COGL_STEREO_LEFT);
68333f
+      paint_texture (stex, paint_tex);
68333f
+      if (stereo)
68333f
+	cogl_framebuffer_set_stereo_mode (fb, COGL_STEREO_BOTH);
68333f
+    }
68333f
+
68333f
+  if (paint_tex_right != NULL)
68333f
+    {
68333f
+      cogl_framebuffer_set_stereo_mode (fb, COGL_STEREO_RIGHT);
68333f
+      paint_texture (stex, paint_tex_right);
68333f
+      cogl_framebuffer_set_stereo_mode (fb, COGL_STEREO_BOTH);
68333f
+    }
68333f
+}
68333f
+
68333f
+static void
68333f
 meta_shaped_texture_pick (ClutterActor       *actor,
68333f
 			  const ClutterColor *color)
68333f
 {
68333f
@@ -392,6 +441,12 @@ meta_shaped_texture_set_create_mipmaps (MetaShapedTexture *stex,
68333f
       base_texture = create_mipmaps ?
68333f
         COGL_TEXTURE (priv->texture) : NULL;
68333f
       meta_texture_tower_set_base_texture (priv->paint_tower, base_texture);
68333f
+
68333f
+      if (priv->stereo)
68333f
+	{
68333f
+	  base_texture = create_mipmaps ? COGL_TEXTURE (priv->texture_right) : NULL;
68333f
+	  meta_texture_tower_set_base_texture (priv->paint_tower_right, base_texture);
68333f
+	}
68333f
     }
68333f
 }
68333f
 
68333f
@@ -435,13 +490,16 @@ meta_shaped_texture_update_area (MetaShapedTexture *stex,
68333f
                                        x, y, width, height);
68333f
 
68333f
   meta_texture_tower_update_area (priv->paint_tower, x, y, width, height);
68333f
+  if (priv->stereo)
68333f
+    meta_texture_tower_update_area (priv->paint_tower_right, x, y, width, height);
68333f
 
68333f
   clutter_actor_queue_redraw_with_clip (CLUTTER_ACTOR (stex), &clip);
68333f
 }
68333f
 
68333f
 static void
68333f
 set_cogl_texture (MetaShapedTexture    *stex,
68333f
-                  CoglTexturePixmapX11 *cogl_tex)
68333f
+                  CoglTexturePixmapX11 *cogl_tex,
68333f
+                  gboolean              stereo)
68333f
 {
68333f
   MetaShapedTexturePrivate *priv;
68333f
   guint width, height;
68333f
@@ -452,9 +510,17 @@ set_cogl_texture (MetaShapedTexture    *stex,
68333f
 
68333f
   if (priv->texture != NULL)
68333f
     cogl_object_unref (priv->texture);
68333f
+  if (priv->texture_right != NULL)
68333f
+    cogl_object_unref (priv->texture_right);
68333f
 
68333f
+  priv->stereo = stereo;
68333f
   priv->texture = cogl_tex;
68333f
 
68333f
+  if (priv->stereo)
68333f
+    priv->texture_right = cogl_texture_pixmap_x11_new_right ((CoglTexturePixmapX11 *)cogl_tex);
68333f
+  else
68333f
+    priv->texture_right = NULL;
68333f
+
68333f
   if (priv->pipeline != NULL)
68333f
     cogl_pipeline_set_layer_texture (priv->pipeline, 0, COGL_TEXTURE (cogl_tex));
68333f
 
68333f
@@ -493,7 +559,8 @@ set_cogl_texture (MetaShapedTexture    *stex,
68333f
  */
68333f
 void
68333f
 meta_shaped_texture_set_pixmap (MetaShapedTexture *stex,
68333f
-                                Pixmap             pixmap)
68333f
+                                Pixmap             pixmap,
68333f
+                                gboolean           stereo)
68333f
 {
68333f
   MetaShapedTexturePrivate *priv;
68333f
 
68333f
@@ -501,23 +568,44 @@ meta_shaped_texture_set_pixmap (MetaShapedTexture *stex,
68333f
 
68333f
   priv = stex->priv;
68333f
 
68333f
-  if (priv->pixmap == pixmap)
68333f
+  if (priv->pixmap == pixmap && priv->stereo == stereo)
68333f
     return;
68333f
 
68333f
   priv->pixmap = pixmap;
68333f
+  priv->stereo = stereo;
68333f
 
68333f
   if (pixmap != None)
68333f
     {
68333f
       CoglContext *ctx =
68333f
         clutter_backend_get_cogl_context (clutter_get_default_backend ());
68333f
-      set_cogl_texture (stex, cogl_texture_pixmap_x11_new (ctx, pixmap, FALSE, NULL));
68333f
+      CoglTexturePixmapX11 *texture;
68333f
+      if (priv->stereo)
68333f
+        texture = cogl_texture_pixmap_x11_new_left (ctx, pixmap, FALSE, NULL);
68333f
+      else
68333f
+        texture = cogl_texture_pixmap_x11_new (ctx, pixmap, FALSE, NULL);
68333f
+      set_cogl_texture (stex, texture, stereo);
68333f
     }
68333f
   else
68333f
-    set_cogl_texture (stex, NULL);
68333f
+    set_cogl_texture (stex, NULL, stereo);
68333f
+
68333f
+  if (priv->stereo)
68333f
+    {
68333f
+      if (priv->paint_tower_right == NULL)
68333f
+	priv->paint_tower_right = meta_texture_tower_new ();
68333f
+    }
68333f
+  else
68333f
+    {
68333f
+      g_clear_pointer (&priv->paint_tower_right, meta_texture_tower_free);
68333f
+    }
68333f
 
68333f
   if (priv->create_mipmaps)
68333f
-    meta_texture_tower_set_base_texture (priv->paint_tower,
68333f
-                                         COGL_TEXTURE (priv->texture));
68333f
+    {
68333f
+      meta_texture_tower_set_base_texture (priv->paint_tower,
68333f
+                                           COGL_TEXTURE (priv->texture));
68333f
+      if (priv->stereo)
68333f
+	meta_texture_tower_set_base_texture (priv->paint_tower_right,
68333f
+					     COGL_TEXTURE (priv->texture_right));
68333f
+    }
68333f
 }
68333f
 
68333f
 /**
68333f
diff --git a/src/compositor/meta-window-actor-private.h b/src/compositor/meta-window-actor-private.h
68333f
index 90a9e35..914a8db 100644
68333f
--- a/src/compositor/meta-window-actor-private.h
68333f
+++ b/src/compositor/meta-window-actor-private.h
68333f
@@ -66,4 +66,11 @@ void meta_window_actor_reset_visible_regions      (MetaWindowActor *self);
68333f
 void meta_window_actor_effect_completed (MetaWindowActor *actor,
68333f
                                          gulong           event);
68333f
 
68333f
+void     meta_window_actor_stereo_notify (MetaWindowActor *actor,
68333f
+                                          gboolean         stereo_tree);
68333f
+
68333f
+gboolean meta_window_actor_is_stereo (MetaWindowActor *actor);
68333f
+
68333f
+void meta_window_actor_detach (MetaWindowActor *self);
68333f
+
68333f
 #endif /* META_WINDOW_ACTOR_PRIVATE_H */
68333f
diff --git a/src/compositor/meta-window-actor.c b/src/compositor/meta-window-actor.c
68333f
index 42d1257..1a11d0e 100644
68333f
--- a/src/compositor/meta-window-actor.c
68333f
+++ b/src/compositor/meta-window-actor.c
68333f
@@ -108,6 +108,7 @@ struct _MetaWindowActorPrivate
68333f
   guint		    visible                : 1;
68333f
   guint		    mapped                 : 1;
68333f
   guint		    argb32                 : 1;
68333f
+  guint		    stereo                 : 1;
68333f
   guint		    disposed               : 1;
68333f
   guint             redecorating           : 1;
68333f
 
68333f
@@ -175,7 +176,6 @@ static gboolean meta_window_actor_get_paint_volume (ClutterActor       *actor,
68333f
                                                     ClutterPaintVolume *volume);
68333f
 
68333f
 
68333f
-static void     meta_window_actor_detach     (MetaWindowActor *self);
68333f
 static gboolean meta_window_actor_has_shadow (MetaWindowActor *self);
68333f
 
68333f
 static void meta_window_actor_handle_updates (MetaWindowActor *self);
68333f
@@ -362,6 +362,9 @@ meta_window_actor_constructed (GObject *object)
68333f
   if (format && format->type == PictTypeDirect && format->direct.alphaMask)
68333f
     priv->argb32 = TRUE;
68333f
 
68333f
+  priv->stereo = meta_compositor_window_is_stereo (screen, xwindow);
68333f
+  meta_compositor_select_stereo_notify (screen, xwindow);
68333f
+
68333f
   if (!priv->actor)
68333f
     {
68333f
       priv->actor = meta_shaped_texture_new ();
68333f
@@ -1218,7 +1221,7 @@ meta_window_actor_effect_completed (MetaWindowActor *self,
68333f
  * when the window is unmapped or when we want to update to a new
68333f
  * pixmap for a new size.
68333f
  */
68333f
-static void
68333f
+void
68333f
 meta_window_actor_detach (MetaWindowActor *self)
68333f
 {
68333f
   MetaWindowActorPrivate *priv     = self->priv;
68333f
@@ -1234,7 +1237,7 @@ meta_window_actor_detach (MetaWindowActor *self)
68333f
    * pixmap, but it certainly doesn't work with current DRI/Mesa
68333f
    */
68333f
   meta_shaped_texture_set_pixmap (META_SHAPED_TEXTURE (priv->actor),
68333f
-                                  None);
68333f
+                                  None, FALSE);
68333f
   cogl_flush();
68333f
 
68333f
   XFreePixmap (xdisplay, priv->back_pixmap);
68333f
@@ -1823,7 +1826,7 @@ check_needs_pixmap (MetaWindowActor *self)
68333f
                                                 FALSE);
68333f
 
68333f
       meta_shaped_texture_set_pixmap (META_SHAPED_TEXTURE (priv->actor),
68333f
-                                      priv->back_pixmap);
68333f
+                                      priv->back_pixmap, priv->stereo);
68333f
 
68333f
       texture = meta_shaped_texture_get_texture (META_SHAPED_TEXTURE (priv->actor));
68333f
 
68333f
@@ -2575,3 +2578,19 @@ meta_window_actor_set_updates_frozen (MetaWindowActor *self,
68333f
         meta_window_actor_thaw (self);
68333f
     }
68333f
 }
68333f
+
68333f
+void
68333f
+meta_window_actor_stereo_notify (MetaWindowActor *self,
68333f
+                                 gboolean         stereo_tree)
68333f
+{
68333f
+  MetaWindowActorPrivate *priv = self->priv;
68333f
+
68333f
+  priv->stereo = stereo_tree;
68333f
+  meta_window_actor_detach (self);
68333f
+}
68333f
+
68333f
+gboolean
68333f
+meta_window_actor_is_stereo (MetaWindowActor *self)
68333f
+{
68333f
+  return self->priv->stereo;
68333f
+}
68333f
diff --git a/src/core/main.c b/src/core/main.c
68333f
index d5bde44..8092afc 100644
68333f
--- a/src/core/main.c
68333f
+++ b/src/core/main.c
68333f
@@ -444,6 +444,8 @@ meta_init (void)
68333f
 
68333f
   meta_restart_init ();
68333f
 
68333f
+  meta_stereo_init ();
68333f
+
68333f
   /*
68333f
    * Clutter can only be initialized after the UI.
68333f
    */
68333f
diff --git a/src/core/stereo.c b/src/core/stereo.c
68333f
new file mode 100644
68333f
index 0000000..d16a210
68333f
--- /dev/null
68333f
+++ b/src/core/stereo.c
68333f
@@ -0,0 +1,144 @@
68333f
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
68333f
+
68333f
+/*
68333f
+ * Copyright (C) 2014 Red Hat, Inc.
68333f
+ *
68333f
+ * This program is free software; you can redistribute it and/or
68333f
+ * modify it under the terms of the GNU General Public License as
68333f
+ * published by the Free Software Foundation; either version 2 of the
68333f
+ * License, or (at your option) any later version.
68333f
+ *
68333f
+ * This program is distributed in the hope that it will be useful, but
68333f
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
68333f
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
68333f
+ * General Public License for more details.
68333f
+ *
68333f
+ * You should have received a copy of the GNU General Public License
68333f
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
68333f
+ */
68333f
+
68333f
+/*
68333f
+ * SECTION:stereo
68333f
+ * @short_description: Keep track of whether we are a stereo compositor
68333f
+ *
68333f
+ * With GLX, we need to use a different GL context for stereo and
68333f
+ * non-stereo support. Support for multiple GL contexts is unfinished
68333f
+ * in Cogl and entirely lacking in Clutter, so it's by far easier
68333f
+ * to just restart Mutter when we detect a stereo window.
68333f
+ *
68333f
+ * A property _MUTTER_ENABLE_STEREO is maintained on the root window
68333f
+ * to know whether we should initialize clutter for stereo or not.
68333f
+ * When the presence or absence of stereo windows mismatches the
68333f
+ * stereo-enabled state for a sufficiently long period of time,
68333f
+ * we restart Mutter.
68333f
+ */
68333f
+
68333f
+#include <config.h>
68333f
+
68333f
+#include <clutter/x11/clutter-x11.h>
68333f
+#include <gio/gunixinputstream.h>
68333f
+#include <X11/Xatom.h>
68333f
+
68333f
+#include <meta/main.h>
68333f
+#include "ui.h"
68333f
+#include <meta/util.h>
68333f
+#include "display-private.h"
68333f
+#include "stereo.h"
68333f
+
68333f
+static guint stereo_switch_id = 0;
68333f
+static gboolean stereo_enabled = FALSE;
68333f
+/* -1 so the first time meta_stereo_set_have_stereo_windows() is called
68333f
+ * we avoid the short-circuit and set up a timeout to restart
68333f
+ * if necessary */
68333f
+static gboolean stereo_have_windows = (gboolean)-1;
68333f
+static gboolean stereo_restart = FALSE;
68333f
+
68333f
+#define STEREO_ENABLE_WAIT 1000
68333f
+#define STEREO_DISABLE_WAIT 5000
68333f
+
68333f
+void
68333f
+meta_stereo_init (void)
68333f
+{
68333f
+  Display *xdisplay = meta_ui_get_display ();
68333f
+  Window root = DefaultRootWindow (xdisplay);
68333f
+  Atom atom_enable_stereo = XInternAtom (xdisplay, "_MUTTER_ENABLE_STEREO", False);
68333f
+  Atom type;
68333f
+  int format;
68333f
+  unsigned long n_items, bytes_after;
68333f
+  guchar *data;
68333f
+
68333f
+  XGetWindowProperty (xdisplay, root, atom_enable_stereo,
68333f
+                      0, 1, False, XA_INTEGER,
68333f
+                      &type, &format, &n_items, &bytes_after, &data);
68333f
+  if (type == XA_INTEGER)
68333f
+    {
68333f
+      if (format == 32 && n_items == 1 && bytes_after == 0)
68333f
+        {
68333f
+          stereo_enabled = *(long *)data;
68333f
+        }
68333f
+      else
68333f
+        {
68333f
+          meta_warning ("Bad value for _MUTTER_ENABLE_STEREO property\n");
68333f
+        }
68333f
+
68333f
+      XFree (data);
68333f
+    }
68333f
+  else if (type != None)
68333f
+    {
68333f
+      meta_warning ("Bad type for _MUTTER_ENABLE_STEREO property\n");
68333f
+    }
68333f
+
68333f
+  meta_verbose ("On startup, _MUTTER_ENABLE_STEREO=%s",
68333f
+                stereo_enabled ? "yes" : "no");
68333f
+  clutter_x11_set_use_stereo_stage (stereo_enabled);
68333f
+}
68333f
+
68333f
+static gboolean
68333f
+meta_stereo_switch (gpointer data)
68333f
+{
68333f
+  stereo_switch_id = 0;
68333f
+  stereo_restart = TRUE;
68333f
+
68333f
+  meta_restart (stereo_have_windows ?
68333f
+                _("Enabling stereo...") :
68333f
+                _("Disabling stereo..."));
68333f
+
68333f
+  return FALSE;
68333f
+}
68333f
+
68333f
+void
68333f
+meta_stereo_set_have_stereo_windows (gboolean have_windows)
68333f
+{
68333f
+  have_windows = have_windows != FALSE;
68333f
+
68333f
+  if (!stereo_restart && have_windows != stereo_have_windows)
68333f
+    {
68333f
+      MetaDisplay *display = meta_get_display ();
68333f
+      Display *xdisplay = meta_display_get_xdisplay (display);
68333f
+      Window root = DefaultRootWindow (xdisplay);
68333f
+      Atom atom_enable_stereo = XInternAtom (xdisplay, "_MUTTER_ENABLE_STEREO", False);
68333f
+      long value;
68333f
+
68333f
+      stereo_have_windows = have_windows;
68333f
+
68333f
+      if (stereo_have_windows)
68333f
+        meta_verbose ("Detected stereo windows\n");
68333f
+      else
68333f
+        meta_verbose ("No stereo windows detected\n");
68333f
+
68333f
+      value = stereo_have_windows;
68333f
+      XChangeProperty (xdisplay, root,
68333f
+                       atom_enable_stereo, XA_INTEGER, 32,
68333f
+                       PropModeReplace, (guchar *)&value, 1);
68333f
+
68333f
+      if (stereo_switch_id != 0)
68333f
+        {
68333f
+          g_source_remove (stereo_switch_id);
68333f
+          stereo_switch_id = 0;
68333f
+        }
68333f
+
68333f
+      if (stereo_have_windows != stereo_enabled)
68333f
+        stereo_switch_id = g_timeout_add (stereo_have_windows ? STEREO_ENABLE_WAIT : STEREO_DISABLE_WAIT,
68333f
+                                          meta_stereo_switch, NULL);
68333f
+    }
68333f
+}
68333f
diff --git a/src/core/stereo.h b/src/core/stereo.h
68333f
new file mode 100644
68333f
index 0000000..ccd1d70
68333f
--- /dev/null
68333f
+++ b/src/core/stereo.h
68333f
@@ -0,0 +1,28 @@
68333f
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
68333f
+
68333f
+/*
68333f
+ * Copyright (C) 2014 Red Hat, Inc.
68333f
+ *
68333f
+ * This program is free software; you can redistribute it and/or
68333f
+ * modify it under the terms of the GNU General Public License as
68333f
+ * published by the Free Software Foundation; either version 2 of the
68333f
+ * License, or (at your option) any later version.
68333f
+ *
68333f
+ * This program is distributed in the hope that it will be useful, but
68333f
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
68333f
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
68333f
+ * General Public License for more details.
68333f
+ *
68333f
+ * You should have received a copy of the GNU General Public License
68333f
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
68333f
+ */
68333f
+
68333f
+#ifndef META_STEREO_H
68333f
+#define META_STEREO_H
68333f
+
68333f
+void     meta_stereo_init                    (void);
68333f
+void     meta_stereo_set_have_stereo_windows (gboolean have_windows);
68333f
+gboolean meta_stereo_is_restart              (void);
68333f
+void     meta_stereo_finish_restart          (void);
68333f
+
68333f
+#endif
68333f
diff --git a/src/meta/meta-shaped-texture.h b/src/meta/meta-shaped-texture.h
68333f
index 28fb5f6..fcf33c3 100644
68333f
--- a/src/meta/meta-shaped-texture.h
68333f
+++ b/src/meta/meta-shaped-texture.h
68333f
@@ -76,7 +76,8 @@ void meta_shaped_texture_update_area (MetaShapedTexture *stex,
68333f
                                       int                height);
68333f
 
68333f
 void meta_shaped_texture_set_pixmap (MetaShapedTexture *stex,
68333f
-                                     Pixmap             pixmap);
68333f
+                                     Pixmap             pixmap,
68333f
+                                     gboolean           stereo);
68333f
 
68333f
 CoglTexture * meta_shaped_texture_get_texture (MetaShapedTexture *stex);
68333f
 
68333f
-- 
68333f
1.8.3.1
68333f