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

776610
From 592ed744f97f283be98d494028f7cbd44fdfab6b Mon Sep 17 00:00:00 2001
776610
From: "Owen W. Taylor" <otaylor@fishsoup.net>
776610
Date: Thu, 8 May 2014 18:44:15 -0400
776610
Subject: [PATCH] Add support for quad-buffer stereo
776610
776610
Track the stereo status of windows using the new EXT_stereo_tree
776610
GLX extension.
776610
776610
When stereo is enabled or disabled, a restart is triggered via
776610
meta_restart() after a timeout, setting a _META_ENABLE_STEREO
776610
property on the root window to indicate whether we should
776610
turn on a stereo stage for clutter. The property avoids a loop,
776610
since we need to enable stereo *before* initializing Clutter and GL,
776610
but we need GL to figure out whether we have stereo windows.
776610
776610
Stereo windows are drawn to the stage using new functionality
776610
in Cogl to setup a stereo context, select which buffer to draw
776610
to, and draw either the left or right buffer of a stereo
776610
texture_from_pixmap.
776610
---
776610
 src/Makefile.am                              |   2 +
776610
 src/compositor/compositor-private.h          |   9 ++
776610
 src/compositor/compositor.c                  | 128 ++++++++++++++++
776610
 src/compositor/meta-shaped-texture-private.h |   5 +-
776610
 src/compositor/meta-shaped-texture.c         |  85 +++++++++--
776610
 src/compositor/meta-surface-actor-wayland.c  |   2 +-
776610
 src/compositor/meta-surface-actor-x11.c      |  56 ++++++-
776610
 src/compositor/meta-surface-actor-x11.h      |   5 +
776610
 src/compositor/meta-window-actor-private.h   |   5 +
776610
 src/compositor/meta-window-actor.c           |  22 +++
776610
 src/core/main.c                              |   4 +
776610
 src/core/stereo.c                            | 153 +++++++++++++++++++
776610
 src/core/stereo.h                            |  28 ++++
776610
 src/wayland/meta-wayland-surface.c           |   2 +-
776610
 14 files changed, 483 insertions(+), 23 deletions(-)
776610
 create mode 100644 src/core/stereo.c
776610
 create mode 100644 src/core/stereo.h
776610
776610
diff --git a/src/Makefile.am b/src/Makefile.am
776610
index 8856877d8..26e0e55c2 100644
776610
--- a/src/Makefile.am
776610
+++ b/src/Makefile.am
776610
@@ -315,6 +315,8 @@ libmutter_@LIBMUTTER_API_VERSION@_la_SOURCES =	\
776610
 	core/stack.h				\
776610
 	core/stack-tracker.c			\
776610
 	core/stack-tracker.h			\
776610
+	core/stereo.c				\
776610
+	core/stereo.h				\
776610
 	core/util.c				\
776610
 	meta/util.h				\
776610
 	core/util-private.h			\
776610
diff --git a/src/compositor/compositor-private.h b/src/compositor/compositor-private.h
776610
index 40c0344cc..25cab9280 100644
776610
--- a/src/compositor/compositor-private.h
776610
+++ b/src/compositor/compositor-private.h
776610
@@ -21,6 +21,10 @@ struct _MetaCompositor
776610
   gint64          server_time_query_time;
776610
   gint64          server_time_offset;
776610
 
776610
+  int             glx_opcode;
776610
+  guint           stereo_tree_ext : 1;
776610
+  guint           have_stereo_windows : 1;
776610
+
776610
   guint           server_time_is_monotonic_time : 1;
776610
   guint           no_mipmaps  : 1;
776610
 
776610
@@ -61,6 +65,11 @@ void     meta_end_modal_for_plugin   (MetaCompositor   *compositor,
776610
 gint64 meta_compositor_monotonic_time_to_server_time (MetaDisplay *display,
776610
                                                       gint64       monotonic_time);
776610
 
776610
+gboolean meta_compositor_window_is_stereo     (MetaScreen *screen,
776610
+                                               Window      xwindow);
776610
+void     meta_compositor_select_stereo_notify (MetaScreen *screen,
776610
+                                               Window      xwindow);
776610
+
776610
 void meta_compositor_flash_window (MetaCompositor *compositor,
776610
                                    MetaWindow     *window);
776610
 
776610
diff --git a/src/compositor/compositor.c b/src/compositor/compositor.c
776610
index 8c924d256..e12fb7b58 100644
776610
--- a/src/compositor/compositor.c
776610
+++ b/src/compositor/compositor.c
776610
@@ -70,6 +70,8 @@
776610
 #include "meta-window-group-private.h"
776610
 #include "window-private.h" /* to check window->hidden */
776610
 #include "display-private.h" /* for meta_display_lookup_x_window() and meta_display_cancel_touch() */
776610
+#include "stack-tracker.h"
776610
+#include "stereo.h"
776610
 #include "util-private.h"
776610
 #include "backends/meta-dnd-private.h"
776610
 #include "frame.h"
776610
@@ -487,6 +489,97 @@ redirect_windows (MetaScreen *screen)
776610
     }
776610
 }
776610
 
776610
+#define GLX_STEREO_TREE_EXT        0x20F5
776610
+#define GLX_STEREO_NOTIFY_MASK_EXT 0x00000001
776610
+#define GLX_STEREO_NOTIFY_EXT      0x00000000
776610
+
776610
+typedef struct {
776610
+  int type;
776610
+  unsigned long serial;
776610
+  Bool send_event;
776610
+  Display *display;
776610
+  int extension;
776610
+  int evtype;
776610
+  Drawable window;
776610
+  Bool stereo_tree;
776610
+} StereoNotifyEvent;
776610
+
776610
+static gboolean
776610
+screen_has_stereo_tree_ext (MetaScreen *screen)
776610
+{
776610
+  MetaDisplay *display = meta_screen_get_display (screen);
776610
+  Display     *xdisplay = meta_display_get_xdisplay (display);
776610
+  const char  *extensions_string;
776610
+
776610
+  static const char * (*query_extensions_string) (Display *display,
776610
+                                                  int      screen);
776610
+
776610
+  if (query_extensions_string == NULL)
776610
+    query_extensions_string =
776610
+      (const char * (*) (Display *, int))
776610
+      cogl_get_proc_address ("glXQueryExtensionsString");
776610
+
776610
+  extensions_string = query_extensions_string (xdisplay,
776610
+                                               meta_screen_get_screen_number (screen));
776610
+
776610
+  return extensions_string && strstr (extensions_string, "EXT_stereo_tree") != 0;
776610
+}
776610
+
776610
+#include <GL/gl.h>
776610
+
776610
+gboolean
776610
+meta_compositor_window_is_stereo (MetaScreen *screen,
776610
+                                  Window      xwindow)
776610
+{
776610
+  MetaCompositor *compositor = get_compositor_for_screen (screen);
776610
+  MetaDisplay    *display = meta_screen_get_display (screen);
776610
+  Display        *xdisplay = meta_display_get_xdisplay (display);
776610
+
776610
+  static int (*query_drawable) (Display      *dpy,
776610
+                                Drawable      draw,
776610
+                                int           attribute,
776610
+                                unsigned int *value);
776610
+
776610
+  if (compositor->stereo_tree_ext)
776610
+    {
776610
+      unsigned int stereo_tree = 0;
776610
+
776610
+      if (query_drawable == NULL)
776610
+        query_drawable =
776610
+          (int (*) (Display *, Drawable, int, unsigned int *))
776610
+          cogl_get_proc_address ("glXQueryDrawable");
776610
+
776610
+      query_drawable (xdisplay, xwindow, GLX_STEREO_TREE_EXT, &stereo_tree);
776610
+
776610
+      return stereo_tree != 0;
776610
+    }
776610
+  else
776610
+    return FALSE;
776610
+}
776610
+
776610
+void
776610
+meta_compositor_select_stereo_notify (MetaScreen *screen,
776610
+                                      Window      xwindow)
776610
+{
776610
+  MetaCompositor *compositor = get_compositor_for_screen (screen);
776610
+  MetaDisplay    *display = meta_screen_get_display (screen);
776610
+  Display        *xdisplay = meta_display_get_xdisplay (display);
776610
+
776610
+  static void (*select_event) (Display      *dpy,
776610
+                               Drawable      draw,
776610
+                               unsigned long event_mask);
776610
+
776610
+  if (compositor->stereo_tree_ext)
776610
+    {
776610
+      if (select_event == NULL)
776610
+        select_event =
776610
+          (void (*) (Display *, Drawable, unsigned long))
776610
+          cogl_get_proc_address ("glXSelectEvent");
776610
+
776610
+      select_event (xdisplay, xwindow, GLX_STEREO_NOTIFY_MASK_EXT);
776610
+    }
776610
+}
776610
+
776610
 void
776610
 meta_compositor_manage (MetaCompositor *compositor)
776610
 {
776610
@@ -495,6 +588,8 @@ meta_compositor_manage (MetaCompositor *compositor)
776610
   MetaScreen *screen = display->screen;
776610
   MetaBackend *backend = meta_get_backend ();
776610
 
776610
+  compositor->stereo_tree_ext = screen_has_stereo_tree_ext (screen);
776610
+
776610
   meta_screen_set_cm_selection (display->screen);
776610
 
776610
   compositor->stage = meta_backend_get_stage (backend);
776610
@@ -759,6 +854,23 @@ meta_compositor_process_event (MetaCompositor *compositor,
776610
       if (window)
776610
         process_damage (compositor, (XDamageNotifyEvent *) event, window);
776610
     }
776610
+  else if (!meta_is_wayland_compositor () &&
776610
+           event->type == GenericEvent &&
776610
+           event->xcookie.extension == compositor->glx_opcode)
776610
+    {
776610
+      if (event->xcookie.evtype == GLX_STEREO_NOTIFY_EXT)
776610
+        {
776610
+          StereoNotifyEvent *stereo_event = (StereoNotifyEvent *)(event->xcookie.data);
776610
+          window = meta_display_lookup_x_window (compositor->display, stereo_event->window);
776610
+
776610
+          if (window != NULL)
776610
+            {
776610
+              MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
776610
+              meta_window_actor_stereo_notify (window_actor, stereo_event->stereo_tree);
776610
+              meta_stack_tracker_queue_sync_stack (window->screen->stack_tracker);
776610
+            }
776610
+        }
776610
+    }
776610
 
776610
   if (compositor->have_x11_sync_object)
776610
     meta_sync_ring_handle_event (event);
776610
@@ -969,6 +1081,7 @@ meta_compositor_sync_stack (MetaCompositor  *compositor,
776610
 			    GList	    *stack)
776610
 {
776610
   GList *old_stack;
776610
+  int stereo_window_count = 0;
776610
 
776610
   /* This is painful because hidden windows that we are in the process
776610
    * of animating out of existence. They'll be at the bottom of the
776610
@@ -1044,6 +1157,8 @@ meta_compositor_sync_stack (MetaCompositor  *compositor,
776610
        * near the front of the other.)
776610
        */
776610
       compositor->windows = g_list_prepend (compositor->windows, actor);
776610
+      if (meta_window_actor_is_stereo (actor))
776610
+        stereo_window_count++;
776610
 
776610
       stack = g_list_remove (stack, window);
776610
       old_stack = g_list_remove (old_stack, actor);
776610
@@ -1051,6 +1166,8 @@ meta_compositor_sync_stack (MetaCompositor  *compositor,
776610
 
776610
   sync_actor_stacking (compositor);
776610
 
776610
+  meta_stereo_set_have_stereo_windows (stereo_window_count > 0);
776610
+
776610
   if (compositor->top_window_actor)
776610
     g_signal_handlers_disconnect_by_func (compositor->top_window_actor,
776610
                                           on_top_window_actor_destroyed,
776610
@@ -1259,6 +1376,17 @@ meta_compositor_new (MetaDisplay *display)
776610
                                            meta_post_paint_func,
776610
                                            compositor,
776610
                                            NULL);
776610
+  if (!meta_is_wayland_compositor ())
776610
+    {
776610
+      Display *xdisplay = meta_display_get_xdisplay (display);
776610
+      int glx_major_opcode, glx_first_event, glx_first_error;
776610
+
776610
+      if (XQueryExtension (xdisplay,
776610
+                           "GLX",
776610
+                           &glx_major_opcode, &glx_first_event, &glx_first_error))
776610
+        compositor->glx_opcode = glx_major_opcode;
776610
+    }
776610
+
776610
   return compositor;
776610
 }
776610
 
776610
diff --git a/src/compositor/meta-shaped-texture-private.h b/src/compositor/meta-shaped-texture-private.h
776610
index 5b3f283c2..189a95312 100644
776610
--- a/src/compositor/meta-shaped-texture-private.h
776610
+++ b/src/compositor/meta-shaped-texture-private.h
776610
@@ -30,8 +30,9 @@
776610
 #include <meta/meta-shaped-texture.h>
776610
 
776610
 ClutterActor *meta_shaped_texture_new (void);
776610
-void meta_shaped_texture_set_texture (MetaShapedTexture *stex,
776610
-                                      CoglTexture       *texture);
776610
+void meta_shaped_texture_set_textures (MetaShapedTexture *stex,
776610
+                                       CoglTexture       *texture,
776610
+                                       CoglTexture       *texture_right);
776610
 void meta_shaped_texture_set_is_y_inverted (MetaShapedTexture *stex,
776610
                                             gboolean           is_y_inverted);
776610
 void meta_shaped_texture_set_snippet (MetaShapedTexture *stex,
776610
diff --git a/src/compositor/meta-shaped-texture.c b/src/compositor/meta-shaped-texture.c
776610
index 8de173bf7..e40bf9d9c 100644
776610
--- a/src/compositor/meta-shaped-texture.c
776610
+++ b/src/compositor/meta-shaped-texture.c
776610
@@ -89,8 +89,10 @@ typedef struct
776610
 struct _MetaShapedTexturePrivate
776610
 {
776610
   MetaTextureTower *paint_tower;
776610
+  MetaTextureTower *paint_tower_right;
776610
 
776610
   CoglTexture *texture;
776610
+  CoglTexture *texture_right;
776610
   CoglTexture *mask_texture;
776610
   CoglSnippet *snippet;
776610
 
776610
@@ -161,8 +163,10 @@ meta_shaped_texture_init (MetaShapedTexture *self)
776610
   priv = self->priv = META_SHAPED_TEXTURE_GET_PRIVATE (self);
776610
 
776610
   priv->paint_tower = meta_texture_tower_new ();
776610
+  priv->paint_tower_right = NULL; /* demand create */
776610
 
776610
   priv->texture = NULL;
776610
+  priv->texture_right = NULL;
776610
   priv->mask_texture = NULL;
776610
   priv->create_mipmaps = TRUE;
776610
   priv->is_y_inverted = TRUE;
776610
@@ -229,11 +233,11 @@ meta_shaped_texture_dispose (GObject *object)
776610
   MetaShapedTexture *self = (MetaShapedTexture *) object;
776610
   MetaShapedTexturePrivate *priv = self->priv;
776610
 
776610
-  if (priv->paint_tower)
776610
-    meta_texture_tower_free (priv->paint_tower);
776610
-  priv->paint_tower = NULL;
776610
+  g_clear_pointer (&priv->paint_tower, meta_texture_tower_free);
776610
+  g_clear_pointer (&priv->paint_tower_right, meta_texture_tower_free);
776610
 
776610
   g_clear_pointer (&priv->texture, cogl_object_unref);
776610
+  g_clear_pointer (&priv->texture_right, cogl_object_unref);
776610
   g_clear_pointer (&priv->opaque_region, cairo_region_destroy);
776610
 
776610
   meta_shaped_texture_set_mask_texture (self, NULL);
776610
@@ -431,8 +435,9 @@ paint_clipped_rectangle (CoglFramebuffer       *fb,
776610
 }
776610
 
776610
 static void
776610
-set_cogl_texture (MetaShapedTexture *stex,
776610
-                  CoglTexture       *cogl_tex)
776610
+set_cogl_textures (MetaShapedTexture *stex,
776610
+                   CoglTexture       *cogl_tex,
776610
+                   CoglTexture       *cogl_tex_right)
776610
 {
776610
   MetaShapedTexturePrivate *priv;
776610
   guint width, height;
776610
@@ -443,10 +448,13 @@ set_cogl_texture (MetaShapedTexture *stex,
776610
 
776610
   if (priv->texture)
776610
     cogl_object_unref (priv->texture);
776610
+  if (priv->texture_right)
776610
+    cogl_object_unref (priv->texture_right);
776610
 
776610
   g_clear_pointer (&priv->saved_base_surface, cairo_surface_destroy);
776610
 
776610
   priv->texture = cogl_tex;
776610
+  priv->texture_right = cogl_tex_right;
776610
 
776610
   if (cogl_tex != NULL)
776610
     {
776610
@@ -460,6 +468,9 @@ set_cogl_texture (MetaShapedTexture *stex,
776610
       height = 0;
776610
     }
776610
 
776610
+  if (cogl_tex_right != NULL)
776610
+    cogl_object_ref (cogl_tex_right);
776610
+
776610
   if (priv->tex_width != width ||
776610
       priv->tex_height != height)
776610
     {
776610
@@ -475,8 +486,23 @@ set_cogl_texture (MetaShapedTexture *stex,
776610
    * previous buffer. We only queue a redraw in response to surface
776610
    * damage. */
776610
 
776610
+  if (cogl_tex_right != NULL)
776610
+    {
776610
+      if (priv->paint_tower_right == NULL)
776610
+        priv->paint_tower_right = meta_texture_tower_new ();
776610
+    }
776610
+  else
776610
+    {
776610
+      g_clear_pointer (&priv->paint_tower_right, meta_texture_tower_free);
776610
+    }
776610
+
776610
   if (priv->create_mipmaps)
776610
-    meta_texture_tower_set_base_texture (priv->paint_tower, cogl_tex);
776610
+    {
776610
+      meta_texture_tower_set_base_texture (priv->paint_tower, cogl_tex);
776610
+
776610
+      if (priv->paint_tower_right)
776610
+        meta_texture_tower_set_base_texture (priv->paint_tower_right, cogl_tex_right);
776610
+    }
776610
 }
776610
 
776610
 static void
776610
@@ -485,6 +511,7 @@ do_paint (MetaShapedTexture *stex,
776610
           CoglTexture       *paint_tex,
776610
           cairo_region_t    *clip_region)
776610
 {
776610
+  ClutterActor *actor = CLUTTER_ACTOR (stex);
776610
   MetaShapedTexturePrivate *priv = stex->priv;
776610
   guint tex_width, tex_height;
776610
   guchar opacity;
776610
@@ -700,7 +727,9 @@ meta_shaped_texture_paint (ClutterActor *actor)
776610
   MetaShapedTexture *stex = META_SHAPED_TEXTURE (actor);
776610
   MetaShapedTexturePrivate *priv = stex->priv;
776610
   CoglTexture *paint_tex = NULL;
776610
+  CoglTexture *paint_tex_right = NULL;
776610
   CoglFramebuffer *fb;
776610
+  gboolean stereo;
776610
 
776610
   if (!priv->texture)
776610
     return;
776610
@@ -737,7 +766,32 @@ meta_shaped_texture_paint (ClutterActor *actor)
776610
     return;
776610
 
776610
   fb = cogl_get_draw_framebuffer ();
776610
-  do_paint (META_SHAPED_TEXTURE (actor), fb, paint_tex, priv->clip_region);
776610
+
776610
+  stereo = priv->texture_right && cogl_framebuffer_get_is_stereo (fb);
776610
+
776610
+  if (stereo)
776610
+    {
776610
+      if (priv->create_mipmaps)
776610
+	paint_tex_right = meta_texture_tower_get_paint_texture (priv->paint_tower_right);
776610
+
776610
+      if (!paint_tex_right)
776610
+	paint_tex_right = COGL_TEXTURE (priv->texture_right);
776610
+    }
776610
+  else
776610
+    paint_tex_right = NULL;
776610
+
776610
+  if (stereo)
776610
+    cogl_framebuffer_set_stereo_mode (fb, COGL_STEREO_LEFT);
776610
+  do_paint (stex, fb, paint_tex, priv->clip_region);
776610
+  if (stereo)
776610
+    cogl_framebuffer_set_stereo_mode (fb, COGL_STEREO_BOTH);
776610
+
776610
+  if (paint_tex_right != NULL)
776610
+    {
776610
+      cogl_framebuffer_set_stereo_mode (fb, COGL_STEREO_RIGHT);
776610
+      do_paint (stex, fb, paint_tex_right, priv->clip_region);
776610
+      cogl_framebuffer_set_stereo_mode (fb, COGL_STEREO_BOTH);
776610
+    }
776610
 }
776610
 
776610
 static void
776610
@@ -859,6 +913,12 @@ meta_shaped_texture_set_create_mipmaps (MetaShapedTexture *stex,
776610
       priv->create_mipmaps = create_mipmaps;
776610
       base_texture = create_mipmaps ? priv->texture : NULL;
776610
       meta_texture_tower_set_base_texture (priv->paint_tower, base_texture);
776610
+
776610
+      if (priv->paint_tower_right)
776610
+        {
776610
+          base_texture = create_mipmaps ? priv->texture_right : NULL;
776610
+          meta_texture_tower_set_base_texture (priv->paint_tower_right, base_texture);
776610
+        }
776610
     }
776610
 }
776610
 
776610
@@ -987,6 +1047,8 @@ meta_shaped_texture_update_area (MetaShapedTexture *stex,
776610
   shrink_backing_region (stex, &clip);
776610
 
776610
   meta_texture_tower_update_area (priv->paint_tower, x, y, width, height);
776610
+  if (priv->paint_tower_right)
776610
+    meta_texture_tower_update_area (priv->paint_tower_right, x, y, width, height);
776610
 
776610
   unobscured_region = effective_unobscured_region (stex);
776610
   if (unobscured_region)
776610
@@ -1019,17 +1081,18 @@ meta_shaped_texture_update_area (MetaShapedTexture *stex,
776610
 }
776610
 
776610
 /**
776610
- * meta_shaped_texture_set_texture:
776610
+ * meta_shaped_texture_set_textures:
776610
  * @stex: The #MetaShapedTexture
776610
  * @pixmap: The #CoglTexture to display
776610
  */
776610
 void
776610
-meta_shaped_texture_set_texture (MetaShapedTexture *stex,
776610
-                                 CoglTexture       *texture)
776610
+meta_shaped_texture_set_textures (MetaShapedTexture *stex,
776610
+                                  CoglTexture       *texture,
776610
+                                  CoglTexture       *texture_right)
776610
 {
776610
   g_return_if_fail (META_IS_SHAPED_TEXTURE (stex));
776610
 
776610
-  set_cogl_texture (stex, texture);
776610
+  set_cogl_textures (stex, texture, texture_right);
776610
 }
776610
 
776610
 /**
776610
diff --git a/src/compositor/meta-surface-actor-wayland.c b/src/compositor/meta-surface-actor-wayland.c
776610
index 7505b7d79..f78bce66c 100644
776610
--- a/src/compositor/meta-surface-actor-wayland.c
776610
+++ b/src/compositor/meta-surface-actor-wayland.c
776610
@@ -187,7 +187,7 @@ meta_surface_actor_wayland_dispose (GObject *object)
776610
   MetaShapedTexture *stex =
776610
     meta_surface_actor_get_texture (META_SURFACE_ACTOR (self));
776610
 
776610
-  meta_shaped_texture_set_texture (stex, NULL);
776610
+  meta_shaped_texture_set_textures (stex, NULL, NULL);
776610
   if (priv->surface)
776610
     {
776610
       g_object_remove_weak_pointer (G_OBJECT (priv->surface),
776610
diff --git a/src/compositor/meta-surface-actor-x11.c b/src/compositor/meta-surface-actor-x11.c
776610
index d32aeb68a..52db3808e 100644
776610
--- a/src/compositor/meta-surface-actor-x11.c
776610
+++ b/src/compositor/meta-surface-actor-x11.c
776610
@@ -31,6 +31,7 @@
776610
 #include <cogl/winsys/cogl-texture-pixmap-x11.h>
776610
 
776610
 #include <meta/errors.h>
776610
+#include "compositor-private.h"
776610
 #include "window-private.h"
776610
 #include "meta-shaped-texture-private.h"
776610
 #include "meta-cullable.h"
776610
@@ -43,6 +44,7 @@ struct _MetaSurfaceActorX11Private
776610
   MetaDisplay *display;
776610
 
776610
   CoglTexture *texture;
776610
+  CoglTexture *texture_right;
776610
   Pixmap pixmap;
776610
   Damage damage;
776610
 
776610
@@ -58,6 +60,8 @@ struct _MetaSurfaceActorX11Private
776610
   guint size_changed : 1;
776610
 
776610
   guint unredirected   : 1;
776610
+
776610
+  guint stereo : 1;
776610
 };
776610
 typedef struct _MetaSurfaceActorX11Private MetaSurfaceActorX11Private;
776610
 
776610
@@ -94,7 +98,7 @@ detach_pixmap (MetaSurfaceActorX11 *self)
776610
    * you are supposed to be able to free a GLXPixmap after freeing the underlying
776610
    * pixmap, but it certainly doesn't work with current DRI/Mesa
776610
    */
776610
-  meta_shaped_texture_set_texture (stex, NULL);
776610
+  meta_shaped_texture_set_textures (stex, NULL, NULL);
776610
   cogl_flush ();
776610
 
776610
   meta_error_trap_push (display);
776610
@@ -103,6 +107,7 @@ detach_pixmap (MetaSurfaceActorX11 *self)
776610
   meta_error_trap_pop (display);
776610
 
776610
   g_clear_pointer (&priv->texture, cogl_object_unref);
776610
+  g_clear_pointer (&priv->texture_right, cogl_object_unref);
776610
 }
776610
 
776610
 static void
776610
@@ -114,23 +119,35 @@ set_pixmap (MetaSurfaceActorX11 *self,
776610
   CoglContext *ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
776610
   MetaShapedTexture *stex = meta_surface_actor_get_texture (META_SURFACE_ACTOR (self));
776610
   CoglError *error = NULL;
776610
-  CoglTexture *texture;
776610
+  CoglTexturePixmapX11 *texture;
776610
+  CoglTexturePixmapX11 *texture_right;
776610
 
776610
   g_assert (priv->pixmap == None);
776610
   priv->pixmap = pixmap;
776610
 
776610
-  texture = COGL_TEXTURE (cogl_texture_pixmap_x11_new (ctx, priv->pixmap, FALSE, &error));
776610
+  if (priv->stereo)
776610
+    texture = cogl_texture_pixmap_x11_new_left (ctx, pixmap, FALSE, &error);
776610
+  else
776610
+    texture = cogl_texture_pixmap_x11_new (ctx, pixmap, FALSE, &error);
776610
+
776610
+  if (priv->stereo)
776610
+    texture_right = cogl_texture_pixmap_x11_new_right (texture);
776610
+  else
776610
+    texture_right = NULL;
776610
 
776610
   if (error != NULL)
776610
     {
776610
       g_warning ("Failed to allocate stex texture: %s", error->message);
776610
       cogl_error_free (error);
776610
     }
776610
-  else if (G_UNLIKELY (!cogl_texture_pixmap_x11_is_using_tfp_extension (COGL_TEXTURE_PIXMAP_X11 (texture))))
776610
+  else if (G_UNLIKELY (!cogl_texture_pixmap_x11_is_using_tfp_extension (texture)))
776610
     g_warning ("NOTE: Not using GLX TFP!\n");
776610
 
776610
-  priv->texture = texture;
776610
-  meta_shaped_texture_set_texture (stex, texture);
776610
+  priv->texture = COGL_TEXTURE (texture);
776610
+  if (priv->stereo)
776610
+    priv->texture_right = COGL_TEXTURE (texture_right);
776610
+
776610
+  meta_shaped_texture_set_textures (stex, COGL_TEXTURE (texture), COGL_TEXTURE (texture_right));
776610
 }
776610
 
776610
 static void
776610
@@ -433,8 +450,8 @@ reset_texture (MetaSurfaceActorX11 *self)
776610
   /* Setting the texture to NULL will cause all the FBO's cached by the
776610
    * shaped texture's MetaTextureTower to be discarded and recreated.
776610
    */
776610
-  meta_shaped_texture_set_texture (stex, NULL);
776610
-  meta_shaped_texture_set_texture (stex, priv->texture);
776610
+  meta_shaped_texture_set_textures (stex, NULL, NULL);
776610
+  meta_shaped_texture_set_textures (stex, priv->texture, priv->texture_right);
776610
 }
776610
 
776610
 MetaSurfaceActor *
776610
@@ -443,12 +460,17 @@ meta_surface_actor_x11_new (MetaWindow *window)
776610
   MetaSurfaceActorX11 *self = g_object_new (META_TYPE_SURFACE_ACTOR_X11, NULL);
776610
   MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self);
776610
   MetaDisplay *display = meta_window_get_display (window);
776610
+  Window xwindow;
776610
 
776610
   g_assert (!meta_is_wayland_compositor ());
776610
 
776610
   priv->window = window;
776610
   priv->display = display;
776610
 
776610
+  xwindow = meta_window_x11_get_toplevel_xwindow (window);
776610
+  priv->stereo = meta_compositor_window_is_stereo (display->screen, xwindow);
776610
+  meta_compositor_select_stereo_notify (display->screen, xwindow);
776610
+
776610
   g_signal_connect_object (priv->display, "gl-video-memory-purged",
776610
                            G_CALLBACK (reset_texture), self, G_CONNECT_SWAPPED);
776610
 
776610
@@ -479,3 +501,21 @@ meta_surface_actor_x11_set_size (MetaSurfaceActorX11 *self,
776610
   priv->last_height = height;
776610
   meta_shaped_texture_set_fallback_size (stex, width, height);
776610
 }
776610
+
776610
+void
776610
+meta_surface_actor_x11_stereo_notify (MetaSurfaceActorX11 *self,
776610
+                                      gboolean             stereo_tree)
776610
+{
776610
+  MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self);
776610
+
776610
+  priv->stereo = stereo_tree != FALSE;
776610
+  detach_pixmap (self);
776610
+}
776610
+
776610
+gboolean
776610
+meta_surface_actor_x11_is_stereo (MetaSurfaceActorX11 *self)
776610
+{
776610
+  MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self);
776610
+
776610
+  return priv->stereo;
776610
+}
776610
diff --git a/src/compositor/meta-surface-actor-x11.h b/src/compositor/meta-surface-actor-x11.h
776610
index 0e692ee0f..4b2ecccb1 100644
776610
--- a/src/compositor/meta-surface-actor-x11.h
776610
+++ b/src/compositor/meta-surface-actor-x11.h
776610
@@ -64,6 +64,11 @@ MetaSurfaceActor * meta_surface_actor_x11_new (MetaWindow *window);
776610
 void meta_surface_actor_x11_set_size (MetaSurfaceActorX11 *self,
776610
                                       int width, int height);
776610
 
776610
+void meta_surface_actor_x11_stereo_notify (MetaSurfaceActorX11 *self,
776610
+                                           gboolean             stereo_tree);
776610
+
776610
+gboolean meta_surface_actor_x11_is_stereo (MetaSurfaceActorX11 *self);
776610
+
776610
 G_END_DECLS
776610
 
776610
 #endif /* __META_SURFACE_ACTOR_X11_H__ */
776610
diff --git a/src/compositor/meta-window-actor-private.h b/src/compositor/meta-window-actor-private.h
776610
index ce5e7eadc..5b011cec1 100644
776610
--- a/src/compositor/meta-window-actor-private.h
776610
+++ b/src/compositor/meta-window-actor-private.h
776610
@@ -60,4 +60,9 @@ MetaSurfaceActor *meta_window_actor_get_surface (MetaWindowActor *self);
776610
 void meta_window_actor_update_surface (MetaWindowActor *self);
776610
 MetaWindowActor *meta_window_actor_from_window (MetaWindow *window);
776610
 
776610
+void meta_window_actor_stereo_notify (MetaWindowActor *actor,
776610
+                                      gboolean         stereo_tree);
776610
+
776610
+gboolean meta_window_actor_is_stereo (MetaWindowActor *actor);
776610
+
776610
 #endif /* META_WINDOW_ACTOR_PRIVATE_H */
776610
diff --git a/src/compositor/meta-window-actor.c b/src/compositor/meta-window-actor.c
776610
index b67fb3ce1..80ff5fdd3 100644
776610
--- a/src/compositor/meta-window-actor.c
776610
+++ b/src/compositor/meta-window-actor.c
776610
@@ -2321,3 +2321,25 @@ screen_cast_window_iface_init (MetaScreenCastWindowInterface *iface)
776610
   iface->transform_relative_position = meta_window_actor_transform_relative_position;
776610
   iface->capture_into = meta_window_actor_capture_into;
776610
 }
776610
+
776610
+void
776610
+meta_window_actor_stereo_notify (MetaWindowActor *self,
776610
+                                 gboolean         stereo_tree)
776610
+{
776610
+  MetaWindowActorPrivate *priv = self->priv;
776610
+
776610
+  if (META_IS_SURFACE_ACTOR_X11 (priv->surface))
776610
+    meta_surface_actor_x11_stereo_notify (META_SURFACE_ACTOR_X11 (priv->surface),
776610
+                                          stereo_tree);
776610
+}
776610
+
776610
+gboolean
776610
+meta_window_actor_is_stereo (MetaWindowActor *self)
776610
+{
776610
+  MetaWindowActorPrivate *priv = self->priv;
776610
+
776610
+  if (META_IS_SURFACE_ACTOR_X11 (priv->surface))
776610
+    return meta_surface_actor_x11_is_stereo (META_SURFACE_ACTOR_X11 (priv->surface));
776610
+  else
776610
+    return FALSE;
776610
+}
776610
diff --git a/src/core/main.c b/src/core/main.c
776610
index be7a90feb..828037635 100644
776610
--- a/src/core/main.c
776610
+++ b/src/core/main.c
776610
@@ -47,6 +47,7 @@
776610
 #include <meta/main.h>
776610
 #include "util-private.h"
776610
 #include "display-private.h"
776610
+#include "stereo.h"
776610
 #include <meta/errors.h>
776610
 #include "ui.h"
776610
 #include <meta/prefs.h>
776610
@@ -582,6 +583,9 @@ meta_init (void)
776610
 
776610
   meta_init_backend (backend_gtype);
776610
 
776610
+  if (!meta_is_wayland_compositor ())
776610
+    meta_stereo_init ();
776610
+
776610
   meta_clutter_init ();
776610
 
776610
 #ifdef HAVE_WAYLAND
776610
diff --git a/src/core/stereo.c b/src/core/stereo.c
776610
new file mode 100644
776610
index 000000000..5a232b67c
776610
--- /dev/null
776610
+++ b/src/core/stereo.c
776610
@@ -0,0 +1,153 @@
776610
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
776610
+
776610
+/*
776610
+ * Copyright (C) 2014 Red Hat, Inc.
776610
+ *
776610
+ * This program is free software; you can redistribute it and/or
776610
+ * modify it under the terms of the GNU General Public License as
776610
+ * published by the Free Software Foundation; either version 2 of the
776610
+ * License, or (at your option) any later version.
776610
+ *
776610
+ * This program is distributed in the hope that it will be useful, but
776610
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
776610
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
776610
+ * General Public License for more details.
776610
+ *
776610
+ * You should have received a copy of the GNU General Public License
776610
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
776610
+ */
776610
+
776610
+/*
776610
+ * SECTION:stereo
776610
+ * @short_description: Keep track of whether we are a stereo compositor
776610
+ *
776610
+ * With GLX, we need to use a different GL context for stereo and
776610
+ * non-stereo support. Support for multiple GL contexts is unfinished
776610
+ * in Cogl and entirely lacking in Clutter, so it's by far easier
776610
+ * to just restart Mutter when we detect a stereo window.
776610
+ *
776610
+ * A property _MUTTER_ENABLE_STEREO is maintained on the root window
776610
+ * to know whether we should initialize clutter for stereo or not.
776610
+ * When the presence or absence of stereo windows mismatches the
776610
+ * stereo-enabled state for a sufficiently long period of time,
776610
+ * we restart Mutter.
776610
+ */
776610
+
776610
+#include <config.h>
776610
+
776610
+#include <clutter/x11/clutter-x11.h>
776610
+#include <gio/gunixinputstream.h>
776610
+#include <X11/Xatom.h>
776610
+
776610
+#include <meta/main.h>
776610
+#include "ui.h"
776610
+#include <meta/util.h>
776610
+#include "display-private.h"
776610
+#include "stereo.h"
776610
+#include "util-private.h"
776610
+
776610
+static guint stereo_switch_id = 0;
776610
+static gboolean stereo_enabled = FALSE;
776610
+/* -1 so the first time meta_stereo_set_have_stereo_windows() is called
776610
+ * we avoid the short-circuit and set up a timeout to restart
776610
+ * if necessary */
776610
+static gboolean stereo_have_windows = (gboolean)-1;
776610
+static gboolean stereo_restart = FALSE;
776610
+
776610
+#define STEREO_ENABLE_WAIT 1000
776610
+#define STEREO_DISABLE_WAIT 5000
776610
+
776610
+void
776610
+meta_stereo_init (void)
776610
+{
776610
+  Display *xdisplay;
776610
+  Window root;
776610
+  Atom atom_enable_stereo;
776610
+  Atom type;
776610
+  int format;
776610
+  unsigned long n_items, bytes_after;
776610
+  guchar *data;
776610
+
776610
+  xdisplay = XOpenDisplay (NULL);
776610
+  if (xdisplay == NULL)
776610
+    meta_fatal ("Unable to open X display %s\n", XDisplayName (NULL));
776610
+
776610
+  root = DefaultRootWindow (xdisplay);
776610
+  atom_enable_stereo = XInternAtom (xdisplay, "_MUTTER_ENABLE_STEREO", False);
776610
+
776610
+  XGetWindowProperty (xdisplay, root, atom_enable_stereo,
776610
+                      0, 1, False, XA_INTEGER,
776610
+                      &type, &format, &n_items, &bytes_after, &data);
776610
+  if (type == XA_INTEGER)
776610
+    {
776610
+      if (format == 32 && n_items == 1 && bytes_after == 0)
776610
+        {
776610
+          stereo_enabled = *(long *)data;
776610
+        }
776610
+      else
776610
+        {
776610
+          meta_warning ("Bad value for _MUTTER_ENABLE_STEREO property\n");
776610
+        }
776610
+
776610
+      XFree (data);
776610
+    }
776610
+  else if (type != None)
776610
+    {
776610
+      meta_warning ("Bad type for _MUTTER_ENABLE_STEREO property\n");
776610
+    }
776610
+
776610
+  meta_verbose ("On startup, _MUTTER_ENABLE_STEREO=%s",
776610
+                stereo_enabled ? "yes" : "no");
776610
+  clutter_x11_set_use_stereo_stage (stereo_enabled);
776610
+  XCloseDisplay (xdisplay);
776610
+}
776610
+
776610
+static gboolean
776610
+meta_stereo_switch (gpointer data)
776610
+{
776610
+  stereo_switch_id = 0;
776610
+  stereo_restart = TRUE;
776610
+
776610
+  meta_restart (stereo_have_windows ?
776610
+                _("Enabling stereo...") :
776610
+                _("Disabling stereo..."));
776610
+
776610
+  return FALSE;
776610
+}
776610
+
776610
+void
776610
+meta_stereo_set_have_stereo_windows (gboolean have_windows)
776610
+{
776610
+  have_windows = have_windows != FALSE;
776610
+
776610
+  if (!stereo_restart && have_windows != stereo_have_windows)
776610
+    {
776610
+      MetaDisplay *display = meta_get_display ();
776610
+      Display *xdisplay = meta_display_get_xdisplay (display);
776610
+      Window root = DefaultRootWindow (xdisplay);
776610
+      Atom atom_enable_stereo = XInternAtom (xdisplay, "_MUTTER_ENABLE_STEREO", False);
776610
+      long value;
776610
+
776610
+      stereo_have_windows = have_windows;
776610
+
776610
+      if (stereo_have_windows)
776610
+        meta_verbose ("Detected stereo windows\n");
776610
+      else
776610
+        meta_verbose ("No stereo windows detected\n");
776610
+
776610
+      value = stereo_have_windows;
776610
+      XChangeProperty (xdisplay, root,
776610
+                       atom_enable_stereo, XA_INTEGER, 32,
776610
+                       PropModeReplace, (guchar *)&value, 1);
776610
+
776610
+      if (stereo_switch_id != 0)
776610
+        {
776610
+          g_source_remove (stereo_switch_id);
776610
+          stereo_switch_id = 0;
776610
+        }
776610
+
776610
+      if (stereo_have_windows != stereo_enabled)
776610
+        stereo_switch_id = g_timeout_add (stereo_have_windows ? STEREO_ENABLE_WAIT : STEREO_DISABLE_WAIT,
776610
+                                          meta_stereo_switch, NULL);
776610
+    }
776610
+}
776610
diff --git a/src/core/stereo.h b/src/core/stereo.h
776610
new file mode 100644
776610
index 000000000..ccd1d702a
776610
--- /dev/null
776610
+++ b/src/core/stereo.h
776610
@@ -0,0 +1,28 @@
776610
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
776610
+
776610
+/*
776610
+ * Copyright (C) 2014 Red Hat, Inc.
776610
+ *
776610
+ * This program is free software; you can redistribute it and/or
776610
+ * modify it under the terms of the GNU General Public License as
776610
+ * published by the Free Software Foundation; either version 2 of the
776610
+ * License, or (at your option) any later version.
776610
+ *
776610
+ * This program is distributed in the hope that it will be useful, but
776610
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
776610
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
776610
+ * General Public License for more details.
776610
+ *
776610
+ * You should have received a copy of the GNU General Public License
776610
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
776610
+ */
776610
+
776610
+#ifndef META_STEREO_H
776610
+#define META_STEREO_H
776610
+
776610
+void     meta_stereo_init                    (void);
776610
+void     meta_stereo_set_have_stereo_windows (gboolean have_windows);
776610
+gboolean meta_stereo_is_restart              (void);
776610
+void     meta_stereo_finish_restart          (void);
776610
+
776610
+#endif
776610
diff --git a/src/wayland/meta-wayland-surface.c b/src/wayland/meta-wayland-surface.c
776610
index c9c229e6c..7bc72f166 100644
776610
--- a/src/wayland/meta-wayland-surface.c
776610
+++ b/src/wayland/meta-wayland-surface.c
776610
@@ -676,7 +676,7 @@ meta_wayland_surface_apply_pending_state (MetaWaylandSurface      *surface,
776610
               snippet = meta_wayland_buffer_create_snippet (pending->buffer);
776610
               is_y_inverted = meta_wayland_buffer_is_y_inverted (pending->buffer);
776610
 
776610
-              meta_shaped_texture_set_texture (stex, texture);
776610
+              meta_shaped_texture_set_textures (stex, texture, NULL);
776610
               meta_shaped_texture_set_snippet (stex, snippet);
776610
               meta_shaped_texture_set_is_y_inverted (stex, is_y_inverted);
776610
               g_clear_pointer (&snippet, cogl_object_unref);
776610
-- 
776610
2.20.1
776610