[mutter/wip/nielsdg/add-yuv-support] WIP: wayland: add basic support for some YUV-ish textures



commit 8aa19feb46243aa6bfbd4c2d69f8dd348b29f247
Author: Niels De Graef <Niels DeGraef barco com>
Date:   Wed Nov 14 12:22:02 2018 +0100

    WIP: wayland: add basic support for some YUV-ish textures
    
    Up until now, we didn't support sending YUV textures to the Wayland
    server. This was for several reasons:
    
    * We draw onto an RGBA framebuffer, so any other color format needs to
    be converted to that color space. Since we don't want to lose a lot of
    performance, this is ideally done on the GPU (using shaders).
    * YUV formats can consist of several planes (for example NV12, a common
    format in decoded video frames consists of a Y-plane and a subsampled
    UV-plane). Mutter always assumed that any texture it got was
    representable by a `CoglTexture`, which does not have this kind of
    concept.
    
    To deal with this, we introduce a new "texture": a
    `CoglMultiPlaneTexture` which consists of multiple CoglTextures, each
    representing a plane in the texture we got.
    
    What changes are in this commit:
    * Introduce a new CoglMultiPlaneTexture object
    * Added some extra values to the CoglPixelFormat enum that deal with YUV
    * Make the necessary changes in MetaWaylandBuffer, so that it knows how
    to deal with incoming buffers (for example EGLImages and shm buffers)
    * This also introduces some changes in MetaDmaBuf, as that is also a
    kind of buffer we can receive.

 cogl/cogl/Makefile.am                           |   2 +
 cogl/cogl/cogl-bitmap-conversion.c              |   1 +
 cogl/cogl/cogl-multi-plane-texture.c            | 182 ++++++++++++++++++++
 cogl/cogl/cogl-multi-plane-texture.h            | 176 ++++++++++++++++++++
 cogl/cogl/cogl-types.h                          |  95 ++++++++++-
 cogl/cogl/cogl.c                                | 123 ++++++++++++++
 cogl/cogl/cogl.h                                |   1 +
 cogl/cogl/driver/gl/cogl-texture-2d-gl.c        |   4 +
 cogl/cogl/driver/gl/gl/cogl-driver-gl.c         |   4 +
 cogl/cogl/driver/gl/gl/cogl-texture-driver-gl.c |   6 +
 cogl/cogl/meson.build                           |   2 +
 src/compositor/meta-shaped-texture-private.h    |   2 +-
 src/compositor/meta-shaped-texture.c            | 196 +++++++++++++++-------
 src/compositor/meta-surface-actor-x11.c         |  11 +-
 src/wayland/meta-wayland-buffer.c               | 211 ++++++++++++++++++------
 src/wayland/meta-wayland-buffer.h               |   4 +-
 src/wayland/meta-wayland-cursor-surface.c       |   7 +-
 src/wayland/meta-wayland-dma-buf.c              |   5 +-
 src/wayland/meta-wayland-shell-surface.c        |   6 +-
 src/wayland/meta-wayland-surface.c              |  10 +-
 src/wayland/meta-wayland.c                      |  19 +++
 21 files changed, 934 insertions(+), 133 deletions(-)
---
diff --git a/cogl/cogl/Makefile.am b/cogl/cogl/Makefile.am
index 2654e45f8..e86aa2a37 100644
--- a/cogl/cogl/Makefile.am
+++ b/cogl/cogl/Makefile.am
@@ -105,6 +105,7 @@ cogl_nonintrospected_h = \
        cogl-sub-texture.h            \
        cogl-atlas-texture.h          \
        cogl-meta-texture.h             \
+       cogl-multi-plane-texture.h              \
        cogl-primitive-texture.h        \
        cogl-depth-state.h              \
        cogl-buffer.h           \
@@ -306,6 +307,7 @@ cogl_sources_c = \
        cogl-atlas-texture-private.h          \
        cogl-atlas-texture.c                  \
        cogl-meta-texture.c                     \
+       cogl-multi-plane-texture.c              \
        cogl-primitive-texture.c                \
        cogl-blit.h                             \
        cogl-blit.c                             \
diff --git a/cogl/cogl/cogl-bitmap-conversion.c b/cogl/cogl/cogl-bitmap-conversion.c
index 9d20a47df..13b27cc6b 100644
--- a/cogl/cogl/cogl-bitmap-conversion.c
+++ b/cogl/cogl/cogl-bitmap-conversion.c
@@ -321,6 +321,7 @@ _cogl_bitmap_needs_short_temp_buffer (CoglPixelFormat format)
     case COGL_PIXEL_FORMAT_DEPTH_24_STENCIL_8:
     case COGL_PIXEL_FORMAT_ANY:
     case COGL_PIXEL_FORMAT_YUV:
+    case COGL_PIXEL_FORMAT_NV12:
       g_assert_not_reached ();
 
     case COGL_PIXEL_FORMAT_A_8:
diff --git a/cogl/cogl/cogl-multi-plane-texture.c b/cogl/cogl/cogl-multi-plane-texture.c
new file mode 100644
index 000000000..66840b237
--- /dev/null
+++ b/cogl/cogl/cogl-multi-plane-texture.c
@@ -0,0 +1,182 @@
+/*
+ * Authored By Niels De Graef <niels degraef barco com>
+ *
+ * Copyright (C) 2018 Barco NV
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cogl-config.h"
+
+#include "cogl-object-private.h"
+#include "cogl-multi-plane-texture.h"
+#include "cogl-gtype-private.h"
+
+static const gchar *nv12_to_rgba_shader =
+    "vec4\n"
+    "cogl_nv12_to_rgba (vec2 UV)\n"
+    "{\n"
+    "  vec4 color;\n"
+
+    "  float y = 1.1640625 * (texture2D (cogl_sampler0, UV).x - 0.0625);\n"
+    "  vec2 uv = texture2D (cogl_sampler1, UV).rg;\n"
+    "  uv -= 0.5;\n"
+    "  float u = uv.x;\n"
+    "  float v = uv.y;\n"
+
+    "  color.r = y + 1.59765625 * v;\n"
+    "  color.g = y - 0.390625 * u - 0.8125 * v;\n"
+    "  color.b = y + 2.015625 * u;\n"
+    "  color.a = 1.0;\n"
+
+    "  return color;\n"
+    "}\n";
+
+struct _CoglMultiPlaneTexture
+{
+  CoglObject _parent;
+
+  CoglPixelFormat format;
+
+  guint n_planes;
+  CoglTexture **planes;
+};
+
+static void
+_cogl_multi_plane_texture_free (CoglMultiPlaneTexture *self);
+
+COGL_OBJECT_DEFINE (MultiPlaneTexture, multi_plane_texture);
+COGL_GTYPE_DEFINE_CLASS (MultiPlaneTexture, multi_plane_texture);
+
+
+CoglPixelFormat
+cogl_multi_plane_texture_get_format (CoglMultiPlaneTexture *self)
+{
+  return self->format;
+}
+
+guint
+cogl_multi_plane_texture_get_n_planes (CoglMultiPlaneTexture *self)
+{
+  return self->n_planes;
+}
+
+CoglTexture *
+cogl_multi_plane_texture_get_plane (CoglMultiPlaneTexture *self, guint index)
+{
+  g_return_val_if_fail (self->n_planes > 0, NULL);
+  g_return_val_if_fail (index < self->n_planes, NULL);
+
+  return self->planes[index];
+}
+
+CoglTexture **
+cogl_multi_plane_texture_get_planes (CoglMultiPlaneTexture *self)
+{
+  return self->planes;
+}
+
+guint
+cogl_multi_plane_texture_get_width (CoglMultiPlaneTexture *self)
+{
+  g_return_val_if_fail (self->n_planes > 0, 0);
+
+  return cogl_texture_get_width (self->planes[0]);
+}
+
+guint
+cogl_multi_plane_texture_get_height (CoglMultiPlaneTexture *self)
+{
+  g_return_val_if_fail (self->n_planes > 0, 0);
+
+  return cogl_texture_get_height (self->planes[0]);
+}
+
+void
+cogl_multi_plane_texture_create_color_conversion_snippets (CoglMultiPlaneTexture *self,
+                                                           CoglSnippet **vertex_snippet_out,
+                                                           CoglSnippet **fragment_snippet_out,
+                                                           CoglSnippet **layer_snippet_out)
+{
+  const gchar *global_hook;
+  const gchar *layer_hook;
+
+  switch (self->format)
+    {
+    case COGL_PIXEL_FORMAT_NV12:
+      /* XXX are we using Y_UV or Y_xUxV? Maybe check for RG support? */
+      global_hook = nv12_to_rgba_shader;
+      layer_hook =  "cogl_layer = cogl_nv12_to_rgba(cogl_tex_coord0_in.st);\n";
+      break;
+    default:
+      *vertex_snippet_out = NULL;
+      *fragment_snippet_out = NULL;
+      *layer_snippet_out = NULL;
+      return;
+    }
+
+    *vertex_snippet_out = cogl_snippet_new (COGL_SNIPPET_HOOK_VERTEX_GLOBALS,
+                                            global_hook,
+                                            NULL);
+
+    *fragment_snippet_out = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT_GLOBALS,
+                                              global_hook,
+                                              NULL);
+
+    *layer_snippet_out = cogl_snippet_new (COGL_SNIPPET_HOOK_LAYER_FRAGMENT,
+                                           NULL,
+                                           layer_hook);
+}
+
+static void
+_cogl_multi_plane_texture_free (CoglMultiPlaneTexture *self)
+{
+  guint i = 0;
+
+  for (i = 0; i < self->n_planes; i++)
+    cogl_object_unref (self->planes[i]);
+
+  g_free (self->planes);
+}
+
+CoglMultiPlaneTexture *
+cogl_multi_plane_texture_new (CoglPixelFormat format,
+                              CoglTexture **planes, guint n_planes)
+{
+  CoglMultiPlaneTexture *self = g_slice_new0 (CoglMultiPlaneTexture);
+
+  _cogl_multi_plane_texture_object_new (self);
+
+  self->format = format;
+  self->n_planes = n_planes;
+  self->planes = planes;
+
+  return self;
+}
+
+CoglMultiPlaneTexture *
+cogl_multi_plane_texture_new_single_plane (CoglPixelFormat format,
+                                           CoglTexture *plane)
+{
+  CoglMultiPlaneTexture *self = g_slice_new0 (CoglMultiPlaneTexture);
+
+  _cogl_multi_plane_texture_object_new (self);
+
+  self->format = format;
+  self->n_planes = 1;
+  self->planes = g_malloc (sizeof (CoglTexture *));
+  self->planes[0] = plane;
+
+  return self;
+}
diff --git a/cogl/cogl/cogl-multi-plane-texture.h b/cogl/cogl/cogl-multi-plane-texture.h
new file mode 100644
index 000000000..ae4056ddd
--- /dev/null
+++ b/cogl/cogl/cogl-multi-plane-texture.h
@@ -0,0 +1,176 @@
+/*
+ * Authored By Niels De Graef <niels degraef barco com>
+ *
+ * Copyright (C) 2018 Barco NV
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef __COGL_MULTI_PLANE_TEXTURE_H__
+#define __COGL_MULTI_PLANE_TEXTURE_H__
+
+#include "cogl/cogl-texture.h"
+
+COGL_BEGIN_DECLS
+
+/**
+ * SECTION:cogl-multi-plane-texture
+ * @title: CoglMultiPlaneTexture
+ * @short_description: A non-primitive texture that can have multiple planes.
+ *
+ * #CoglMultiPlaneTexture allows one to deal with non-trivial formats that
+ * have multiple planes, requires subsampling and/or aren't in RGB. A common
+ * example of this are decoded video frames, which often use something in the
+ * YUV colorspace, combined with subsampling.
+ *
+ * The basic idea of a #CoglMultiPlaneTexture is the following:
+ * - Each plane is represented by a separate #CoglTexture. That means that you
+ *   should add each of these planes as a layer to your CoglPipeline.
+ * - When dealing with a color space that is not RGB, you can ask the
+ *   #CoglMultiPlaneTexture to create a shader for you that does the conversion
+ *   in the GPU.
+ * - In case you need to deal with memory access in a format with subsampling,
+ *   you can use cogl_multi_plane_texture_get_width() and its analogous version
+ *   for the height to get the correct size of the texture.
+ */
+
+typedef struct _CoglMultiPlaneTexture CoglMultiPlaneTexture;
+#define COGL_MULTI_PLANE_TEXTURE(tex) ((CoglMultiPlaneTexture *) tex)
+
+
+/**
+ * cogl_multiplane_texture_get_gtype:
+ *
+ * Returns: a #GType that can be used with the GLib type system.
+ */
+GType cogl_multi_plane_texture_get_gtype (void);
+
+/**
+ * cogl_multi_plane_texture_new:
+ * @format: The format of the #CoglMultiPlaneTexture
+ * @planes: (transfer full): The actual planes of the texture
+ * @n_planes: The number of planes
+ *
+ * Creates a #CoglMultiPlaneTexture with the given @format. Each of the
+ * #CoglTexture<!-- -->s represents a plane.
+ *
+ * Returns: (transfer full): A new #CoglMultiPlaneTexture. Use
+ * cogl_object_unref() when you're done with it.
+ */
+CoglMultiPlaneTexture * cogl_multi_plane_texture_new  (CoglPixelFormat format,
+                                                       CoglTexture **planes,
+                                                       guint n_planes);
+
+/**
+ * cogl_multi_plane_texture_new_single_plane:
+ * @format: The format of the #CoglMultiPlaneTexture
+ * @plane: (transfer full): The actual planes of the texture
+ *
+ * Creates a #CoglMultiPlaneTexture for a "simple" texture, i.e. with only one
+ * plane.
+ *
+ * Returns: (transfer full): A new #CoglMultiPlaneTexture. Use
+ * cogl_object_unref() when you're done with it.
+ */
+CoglMultiPlaneTexture * cogl_multi_plane_texture_new_single_plane (CoglPixelFormat format,
+                                                                   CoglTexture *plane);
+
+/**
+ * cogl_multi_plane_texture_get_format:
+ * @self: a #CoglMultiPlaneTexture
+ *
+ * Returns the pixel format that is used by this texture.
+ *
+ * Returns: The pixel format that is used by this #CoglMultiPlaneTexture.
+ */
+CoglPixelFormat cogl_multi_plane_texture_get_format   (CoglMultiPlaneTexture *self);
+
+/**
+ * cogl_multi_plane_texture_get_format:
+ * @self: a #CoglMultiPlaneTexture
+ *
+ * Returns the number of planes for this texture. Note that this is entirely
+ * dependent on the #CoglPixelFormat that is used. For example, simple RGB
+ * textures will have a single plane, while some more convoluted formats like
+ * NV12 and YUV 4:4:4 can have 2 and 3 planes respectively.
+ *
+ * Returns: The number of planes in this #CoglMultiPlaneTexture.
+ */
+guint           cogl_multi_plane_texture_get_n_planes (CoglMultiPlaneTexture *self);
+
+/**
+ * cogl_multi_plane_texture_get_plane:
+ * @self: a #CoglMultiPlaneTexture
+ * @index: the index of the plane
+ *
+ * Returns the n'th plane of the #CoglMultiPlaneTexture. Note that it is a
+ * programming error to use with an index larger than
+ * cogl_multi_plane_texture_get_n_planes().
+ *
+ * Returns: The plane at the given @index.
+ */
+CoglTexture *   cogl_multi_plane_texture_get_plane    (CoglMultiPlaneTexture *self,
+                                                       guint index);
+
+/**
+ * cogl_multi_plane_texture_get_planes:
+ * @self: a #CoglMultiPlaneTexture
+ *
+ * Returns all planes of the #CoglMultiPlaneTexture.
+ *
+ * Returns: (transfer none): The planes of this texture.
+ */
+CoglTexture **  cogl_multi_plane_texture_get_planes   (CoglMultiPlaneTexture *self);
+
+/**
+ * cogl_multi_plane_texture_get_width:
+ * @self: a #CoglMultiPlaneTexture
+ *
+ * Returns the width of the #CoglMultiPlaneTexture. Prefer this over calling
+ * cogl_texture_get_width() on one of the textures, as that might give a
+ * different size when dealing with subsampling.
+ *
+ * Returns: The width of the texture.
+ */
+guint           cogl_multi_plane_texture_get_width    (CoglMultiPlaneTexture *self);
+
+/**
+ * cogl_multi_plane_texture_get_height:
+ * @self: a #CoglMultiPlaneTexture
+ *
+ * Returns the height of the #CoglMultiPlaneTexture. Prefer this over calling
+ * cogl_texture_get_height() on one of the textures, as that might give a
+ * different size when dealing with subsampling.
+ *
+ * Returns: The height of the texture.
+ */
+guint           cogl_multi_plane_texture_get_height   (CoglMultiPlaneTexture *self);
+
+/**
+ * cogl_multi_plane_texture_create_color_conversion_snippets:
+ *
+ * Creates a trio of #CoglSnippets that allow you to use this texture inside
+ * your pipeline. If no such shader is needed (e.g. because you already have
+ * a single-plane RGBA texture), then they will be set to %NULL.
+ */
+void cogl_multi_plane_texture_create_color_conversion_snippets (CoglMultiPlaneTexture *self,
+                                                                CoglSnippet **vertex_snippet_out,
+                                                                CoglSnippet **fragment_snippet_out,
+                                                                CoglSnippet **layer_snippet_out);
+
+COGL_END_DECLS
+
+#endif
diff --git a/cogl/cogl/cogl-types.h b/cogl/cogl/cogl-types.h
index b351cfd2d..5e83b8e6c 100644
--- a/cogl/cogl/cogl-types.h
+++ b/cogl/cogl/cogl-types.h
@@ -269,7 +269,7 @@ typedef struct _CoglTextureVertex       CoglTextureVertex;
  * @COGL_PIXEL_FORMAT_RGB_565: RGB, 16 bits
  * @COGL_PIXEL_FORMAT_RGBA_4444: RGBA, 16 bits
  * @COGL_PIXEL_FORMAT_RGBA_5551: RGBA, 16 bits
- * @COGL_PIXEL_FORMAT_YUV: Not currently supported
+ * @COGL_PIXEL_FORMAT_YUV: Obsolete. See the other YUV-based formats.
  * @COGL_PIXEL_FORMAT_G_8: Single luminance component
  * @COGL_PIXEL_FORMAT_RGB_888: RGB, 24 bits
  * @COGL_PIXEL_FORMAT_BGR_888: BGR, 24 bits
@@ -291,6 +291,35 @@ typedef struct _CoglTextureVertex       CoglTextureVertex;
  * @COGL_PIXEL_FORMAT_BGRA_1010102_PRE: Premultiplied BGRA, 32 bits, 10 bpc
  * @COGL_PIXEL_FORMAT_ARGB_2101010_PRE: Premultiplied ARGB, 32 bits, 10 bpc
  * @COGL_PIXEL_FORMAT_ABGR_2101010_PRE: Premultiplied ABGR, 32 bits, 10 bpc
+ * @COGL_PIXEL_FORMAT_YUYV: YUYV, 32 bits, 16 bpc (Y), 8 bpc (U & V)
+ * @COGL_PIXEL_FORMAT_YVYU: YVYU, 32 bits, 16 bpc (Y), 8 bpc (V & U)
+ * @COGL_PIXEL_FORMAT_UYVY: UYVY, 32 bits, 16 bpc (Y), 8 bpc (V & U)
+ * @COGL_PIXEL_FORMAT_VYUY: VYUV, 32 bits, 16 bpc (Y), 8 bpc (V & U)
+ * @COGL_PIXEL_FORMAT_AYUV: AYUV, 32 bits, 8 bpc
+ * @COGL_PIXEL_FORMAT_XRGB88888_A8: 
+ * @COGL_PIXEL_FORMAT_XBGR88888_A8: 
+ * @COGL_PIXEL_FORMAT_RGBX88888_A8: 
+ * @COGL_PIXEL_FORMAT_BGRX88888_A8: 
+ * @COGL_PIXEL_FORMAT_RGB888_A8: 
+ * @COGL_PIXEL_FORMAT_BGR888_A8: 
+ * @COGL_PIXEL_FORMAT_RGB565_A8: 
+ * @COGL_PIXEL_FORMAT_BGR565_A8: 
+ * @COGL_PIXEL_FORMAT_NV12: 2 planes: 1 Y-plane, 1 UV-plane (2x2 subsampled)
+ * @COGL_PIXEL_FORMAT_NV21: 2 planes: 1 Y-plane, 1 VU-plane (2x2 subsampled)
+ * @COGL_PIXEL_FORMAT_NV16: 2 planes: 1 Y-plane, 1 UV-plane (2x1 subsampled)
+ * @COGL_PIXEL_FORMAT_NV61: 2 planes: 1 Y-plane, 1 VU-plane (2x1 subsampled)
+ * @COGL_PIXEL_FORMAT_NV24: 2 planes: 1 Y-plane, 1 UV-plane
+ * @COGL_PIXEL_FORMAT_NV42: 2 planes: 1 Y-plane, 1 VU-plane
+ * @COGL_PIXEL_FORMAT_YUV410: 3 planes: 1 Y-plane, 1 U-plane (4x4 subsampled), 1 V-plane (4x4 subsampled)
+ * @COGL_PIXEL_FORMAT_YVU410: 3 planes: 1 Y-plane, 1 V-plane (4x4 subsampled), 1 U-plane (4x4 subsampled)
+ * @COGL_PIXEL_FORMAT_YUV411: 3 planes: 1 Y-plane, 1 U-plane (4x1 subsampled), 1 V-plane (4x1 subsampled)
+ * @COGL_PIXEL_FORMAT_YVU411: 3 planes: 1 Y-plane, 1 V-plane (4x1 subsampled), 1 U-plane (4x1 subsampled)
+ * @COGL_PIXEL_FORMAT_YUV420: 3 planes: 1 Y-plane, 1 U-plane (2x2 subsampled), 1 V-plane (2x2 subsampled)
+ * @COGL_PIXEL_FORMAT_YVU420: 3 planes: 1 Y-plane, 1 V-plane (2x2 subsampled), 1 U-plane (2x2 subsampled)
+ * @COGL_PIXEL_FORMAT_YUV422: 3 planes: 1 Y-plane, 1 U-plane (2x1 subsampled), 1 V-plane (2x1 subsampled)
+ * @COGL_PIXEL_FORMAT_YVU422: 3 planes: 1 Y-plane, 1 V-plane (2x1 subsampled), 1 U-plane (2x1 subsampled)
+ * @COGL_PIXEL_FORMAT_YUV444: 3 planes: 1 Y-plane, 1 U-plane, 1 V-plane
+ * @COGL_PIXEL_FORMAT_YVU444: 3 planes: 1 Y-plane, 1 V-plane, 1 U-plane
  *
  * Pixel formats used by Cogl. For the formats with a byte per
  * component, the order of the components specify the order in
@@ -353,9 +382,71 @@ typedef enum { /*< prefix=COGL_PIXEL_FORMAT >*/
   COGL_PIXEL_FORMAT_DEPTH_16  = (9 | COGL_DEPTH_BIT),
   COGL_PIXEL_FORMAT_DEPTH_32  = (3 | COGL_DEPTH_BIT),
 
-  COGL_PIXEL_FORMAT_DEPTH_24_STENCIL_8 = (3 | COGL_DEPTH_BIT | COGL_STENCIL_BIT)
+  COGL_PIXEL_FORMAT_DEPTH_24_STENCIL_8 = (3 | COGL_DEPTH_BIT | COGL_STENCIL_BIT),
+
+
+ /* From here on out, we simply enumerate with sequential values in the most
+  * significant enum byte. See the comments above if you want to know why. */
+
+  /* The following list is basically synced with Linux's <drm_fourcc.h> */
+
+  /* Packed YUV */
+  COGL_PIXEL_FORMAT_YUYV = (1 << 24),
+  COGL_PIXEL_FORMAT_YVYU = (2 << 24),
+  COGL_PIXEL_FORMAT_UYVY = (3 << 24),
+  COGL_PIXEL_FORMAT_VYUY = (4 << 24),
+
+  COGL_PIXEL_FORMAT_AYUV = (5 << 24),
+
+  /* 2 plane RGB + A */
+  COGL_PIXEL_FORMAT_XRGB88888_A8 = ( 6 << 24),
+  COGL_PIXEL_FORMAT_XBGR88888_A8 = ( 7 << 24),
+  COGL_PIXEL_FORMAT_RGBX88888_A8 = ( 8 << 24),
+  COGL_PIXEL_FORMAT_BGRX88888_A8 = ( 9 << 24),
+  COGL_PIXEL_FORMAT_RGB888_A8    = (10 << 24),
+  COGL_PIXEL_FORMAT_BGR888_A8    = (11 << 24),
+  COGL_PIXEL_FORMAT_RGB565_A8    = (12 << 24),
+  COGL_PIXEL_FORMAT_BGR565_A8    = (13 << 24),
+
+  /* 2 plane YUV */
+  COGL_PIXEL_FORMAT_NV12 = (14 << 24),
+  COGL_PIXEL_FORMAT_NV21 = (15 << 24),
+  COGL_PIXEL_FORMAT_NV16 = (16 << 24),
+  COGL_PIXEL_FORMAT_NV61 = (17 << 24),
+  COGL_PIXEL_FORMAT_NV24 = (18 << 24),
+  COGL_PIXEL_FORMAT_NV42 = (19 << 24),
+
+  /* 3 plane YUV */
+  COGL_PIXEL_FORMAT_YUV410 = (20 << 24),
+  COGL_PIXEL_FORMAT_YVU410 = (21 << 24),
+  COGL_PIXEL_FORMAT_YUV411 = (22 << 24),
+  COGL_PIXEL_FORMAT_YVU411 = (23 << 24),
+  COGL_PIXEL_FORMAT_YUV420 = (24 << 24),
+  COGL_PIXEL_FORMAT_YVU420 = (25 << 24),
+  COGL_PIXEL_FORMAT_YUV422 = (26 << 24),
+  COGL_PIXEL_FORMAT_YVU422 = (27 << 24),
+  COGL_PIXEL_FORMAT_YUV444 = (28 << 24),
+  COGL_PIXEL_FORMAT_YVU444 = (29 << 24)
 } CoglPixelFormat;
 
+/**
+ * cogl_pixel_format_get_n_planes:
+ *
+ * Returns the number of planes the given CoglPixelFormat specifies.
+ */
+guint
+cogl_pixel_format_get_n_planes (CoglPixelFormat format);
+
+/**
+ * cogl_pixel_format_get_subsampling_factors:
+ *
+ * Returns the subsampling in both the horizontal as the vertical direction.
+ */
+void
+cogl_pixel_format_get_subsampling_factors (CoglPixelFormat format,
+                                           guint *horizontal_factors,
+                                           guint *vertical_factors);
+
 /**
  * CoglFeatureFlags:
  * @COGL_FEATURE_TEXTURE_RECTANGLE: ARB_texture_rectangle support
diff --git a/cogl/cogl/cogl.c b/cogl/cogl/cogl.c
index 296999010..964026180 100644
--- a/cogl/cogl/cogl.c
+++ b/cogl/cogl/cogl.c
@@ -816,3 +816,126 @@ _cogl_pixel_format_is_endian_dependant (CoglPixelFormat format)
 
   return aligned;
 }
+
+guint
+cogl_pixel_format_get_n_planes (CoglPixelFormat format)
+{
+  switch (format)
+    {
+    default:
+      return 1;
+    case COGL_PIXEL_FORMAT_XRGB88888_A8:
+    case COGL_PIXEL_FORMAT_XBGR88888_A8:
+    case COGL_PIXEL_FORMAT_RGBX88888_A8:
+    case COGL_PIXEL_FORMAT_BGRX88888_A8:
+    case COGL_PIXEL_FORMAT_RGB888_A8:
+    case COGL_PIXEL_FORMAT_BGR888_A8:
+    case COGL_PIXEL_FORMAT_RGB565_A8:
+    case COGL_PIXEL_FORMAT_BGR565_A8:
+    case COGL_PIXEL_FORMAT_NV12:
+    case COGL_PIXEL_FORMAT_NV21:
+    case COGL_PIXEL_FORMAT_NV16:
+    case COGL_PIXEL_FORMAT_NV61:
+    case COGL_PIXEL_FORMAT_NV24:
+    case COGL_PIXEL_FORMAT_NV42:
+      return 2;
+    case COGL_PIXEL_FORMAT_YUV410:
+    case COGL_PIXEL_FORMAT_YVU410:
+    case COGL_PIXEL_FORMAT_YUV411:
+    case COGL_PIXEL_FORMAT_YVU411:
+    case COGL_PIXEL_FORMAT_YUV420:
+    case COGL_PIXEL_FORMAT_YVU420:
+    case COGL_PIXEL_FORMAT_YUV422:
+    case COGL_PIXEL_FORMAT_YVU422:
+    case COGL_PIXEL_FORMAT_YUV444:
+    case COGL_PIXEL_FORMAT_YVU444:
+      return 3;
+    }
+
+  g_assert_not_reached ();
+}
+
+void
+cogl_pixel_format_get_subsampling_factors (CoglPixelFormat format,
+                                           guint *horizontal_factors,
+                                           guint *vertical_factors)
+{
+  switch (format)
+    {
+    /* Packed formats (single plane) */
+    default:
+      horizontal_factors[0] = 1;
+      vertical_factors[0] = 1;
+      break;
+
+    /* 2 planes */
+    case COGL_PIXEL_FORMAT_NV12:
+    case COGL_PIXEL_FORMAT_NV21:
+      horizontal_factors[0] = 1;
+      vertical_factors[0] = 1;
+      horizontal_factors[1] = 2;
+      vertical_factors[1] = 2;
+      break;
+
+    case COGL_PIXEL_FORMAT_XRGB88888_A8:
+    case COGL_PIXEL_FORMAT_XBGR88888_A8:
+    case COGL_PIXEL_FORMAT_RGBX88888_A8:
+    case COGL_PIXEL_FORMAT_BGRX88888_A8:
+    case COGL_PIXEL_FORMAT_RGB888_A8:
+    case COGL_PIXEL_FORMAT_BGR888_A8:
+    case COGL_PIXEL_FORMAT_RGB565_A8:
+    case COGL_PIXEL_FORMAT_BGR565_A8:
+      horizontal_factors[0] = 1;
+      vertical_factors[0] = 1;
+      horizontal_factors[1] = 1;
+      vertical_factors[1] = 1;
+      break;
+
+    /* 3 planes */
+    case COGL_PIXEL_FORMAT_YUV410:
+    case COGL_PIXEL_FORMAT_YVU410:
+      horizontal_factors[0] = 1;
+      vertical_factors[0] = 1;
+      horizontal_factors[1] = 4;
+      vertical_factors[1] = 4;
+      horizontal_factors[2] = 4;
+      vertical_factors[2] = 4;
+      break;
+    case COGL_PIXEL_FORMAT_YUV411:
+    case COGL_PIXEL_FORMAT_YVU411:
+      horizontal_factors[0] = 1;
+      vertical_factors[0] = 1;
+      horizontal_factors[1] = 4;
+      vertical_factors[1] = 1;
+      horizontal_factors[2] = 4;
+      vertical_factors[2] = 1;
+      break;
+    case COGL_PIXEL_FORMAT_YUV420:
+    case COGL_PIXEL_FORMAT_YVU420:
+      horizontal_factors[0] = 1;
+      vertical_factors[0] = 1;
+      horizontal_factors[1] = 2;
+      vertical_factors[1] = 2;
+      horizontal_factors[2] = 2;
+      vertical_factors[2] = 2;
+      break;
+    case COGL_PIXEL_FORMAT_YUV422:
+    case COGL_PIXEL_FORMAT_YVU422:
+      horizontal_factors[0] = 1;
+      vertical_factors[0] = 1;
+      horizontal_factors[1] = 2;
+      vertical_factors[1] = 1;
+      horizontal_factors[2] = 2;
+      vertical_factors[2] = 1;
+      break;
+    case COGL_PIXEL_FORMAT_YUV444:
+    case COGL_PIXEL_FORMAT_YVU444:
+      horizontal_factors[0] = 1;
+      vertical_factors[0] = 1;
+      horizontal_factors[1] = 1;
+      vertical_factors[1] = 1;
+      horizontal_factors[2] = 1;
+      vertical_factors[2] = 1;
+      break;
+    }
+}
diff --git a/cogl/cogl/cogl.h b/cogl/cogl/cogl.h
index 565ea289a..84595b595 100644
--- a/cogl/cogl/cogl.h
+++ b/cogl/cogl/cogl.h
@@ -111,6 +111,7 @@
 #include <cogl/cogl-sub-texture.h>
 #include <cogl/cogl-atlas-texture.h>
 #include <cogl/cogl-meta-texture.h>
+#include <cogl/cogl-multi-plane-texture.h>
 #include <cogl/cogl-primitive-texture.h>
 #include <cogl/cogl-index-buffer.h>
 #include <cogl/cogl-attribute-buffer.h>
diff --git a/cogl/cogl/driver/gl/cogl-texture-2d-gl.c b/cogl/cogl/driver/gl/cogl-texture-2d-gl.c
index ba90998ba..957e20761 100644
--- a/cogl/cogl/driver/gl/cogl-texture-2d-gl.c
+++ b/cogl/cogl/driver/gl/cogl-texture-2d-gl.c
@@ -209,6 +209,8 @@ allocate_from_bitmap (CoglTexture2D *tex_2d,
   GLenum gl_format;
   GLenum gl_type;
 
+  g_warning ("allocate_from_bitmap()");
+
   internal_format =
     _cogl_texture_determine_internal_format (tex, cogl_bitmap_get_format (bmp));
 
@@ -349,6 +351,8 @@ allocate_from_gl_foreign (CoglTexture2D *tex_2d,
   GLint gl_compressed = GL_FALSE;
   GLenum gl_int_format = 0;
 
+  g_warning ("allocate_from_egl_image_foreign()");
+
   if (!ctx->texture_driver->allows_foreign_gl_target (ctx, GL_TEXTURE_2D))
     {
       _cogl_set_error (error,
diff --git a/cogl/cogl/driver/gl/gl/cogl-driver-gl.c b/cogl/cogl/driver/gl/gl/cogl-driver-gl.c
index f7454aa07..e4a932389 100644
--- a/cogl/cogl/driver/gl/gl/cogl-driver-gl.c
+++ b/cogl/cogl/driver/gl/gl/cogl-driver-gl.c
@@ -277,6 +277,10 @@ _cogl_driver_pixel_format_to_gl_with_target (CoglContext *context,
       gltype = GL_UNSIGNED_INT_24_8;
       break;
 
+    case COGL_PIXEL_FORMAT_NV12:
+      g_warning ("FIXME");
+      break;
+
     case COGL_PIXEL_FORMAT_ANY:
     case COGL_PIXEL_FORMAT_YUV:
       g_assert_not_reached ();
diff --git a/cogl/cogl/driver/gl/gl/cogl-texture-driver-gl.c b/cogl/cogl/driver/gl/gl/cogl-texture-driver-gl.c
index dc3c98ba2..e053f5e0e 100644
--- a/cogl/cogl/driver/gl/gl/cogl-texture-driver-gl.c
+++ b/cogl/cogl/driver/gl/gl/cogl-texture-driver-gl.c
@@ -99,6 +99,8 @@ _cogl_texture_driver_gen (CoglContext *ctx,
       g_assert_not_reached();
     }
 
+  g_warning ("_cogl_texture_driver_gen %d", internal_format);
+
   /* If the driver doesn't support alpha textures directly then we'll
    * fake them by setting the swizzle parameters */
   if (internal_format == COGL_PIXEL_FORMAT_A_8 &&
@@ -222,6 +224,8 @@ _cogl_texture_driver_upload_subregion_to_gl (CoglContext *ctx,
   int level_width;
   int level_height;
 
+  g_warning ("uploading subregion to gl");
+
   cogl_texture_get_gl_texture (texture, &gl_handle, &gl_target);
 
   data = _cogl_bitmap_gl_bind (source_bmp, COGL_BUFFER_ACCESS_READ, 0, &internal_error);
@@ -326,6 +330,8 @@ _cogl_texture_driver_upload_to_gl (CoglContext *ctx,
   CoglBool status = TRUE;
   CoglError *internal_error = NULL;
 
+  g_warning ("uploading to gl");
+
   data = _cogl_bitmap_gl_bind (source_bmp,
                                COGL_BUFFER_ACCESS_READ,
                                0, /* hints */
diff --git a/cogl/cogl/meson.build b/cogl/cogl/meson.build
index 8b211d9bd..76a42442b 100644
--- a/cogl/cogl/meson.build
+++ b/cogl/cogl/meson.build
@@ -124,6 +124,7 @@ cogl_nonintrospected_headers = [
   'cogl-sub-texture.h',
   'cogl-atlas-texture.h',
   'cogl-meta-texture.h',
+  'cogl-multi-plane-texture.h',
   'cogl-primitive-texture.h',
   'cogl-depth-state.h',
   'cogl-buffer.h',
@@ -322,6 +323,7 @@ cogl_sources = [
   'cogl-atlas-texture-private.h',
   'cogl-atlas-texture.c',
   'cogl-meta-texture.c',
+  'cogl-multi-plane-texture.c',
   'cogl-primitive-texture.c',
   'cogl-blit.h',
   'cogl-blit.c',
diff --git a/src/compositor/meta-shaped-texture-private.h b/src/compositor/meta-shaped-texture-private.h
index 284f43e36..ac2e82dbb 100644
--- a/src/compositor/meta-shaped-texture-private.h
+++ b/src/compositor/meta-shaped-texture-private.h
@@ -31,7 +31,7 @@
 
 ClutterActor *meta_shaped_texture_new (void);
 void meta_shaped_texture_set_texture (MetaShapedTexture *stex,
-                                      CoglTexture       *texture);
+                                      CoglMultiPlaneTexture *texture);
 void meta_shaped_texture_set_is_y_inverted (MetaShapedTexture *stex,
                                             gboolean           is_y_inverted);
 void meta_shaped_texture_set_snippet (MetaShapedTexture *stex,
diff --git a/src/compositor/meta-shaped-texture.c b/src/compositor/meta-shaped-texture.c
index 919e7a9b5..6165f6c63 100644
--- a/src/compositor/meta-shaped-texture.c
+++ b/src/compositor/meta-shaped-texture.c
@@ -86,7 +86,7 @@ struct _MetaShapedTexturePrivate
 {
   MetaTextureTower *paint_tower;
 
-  CoglTexture *texture;
+  CoglMultiPlaneTexture *texture;
   CoglTexture *mask_texture;
   CoglSnippet *snippet;
 
@@ -197,10 +197,11 @@ static void
 meta_shaped_texture_reset_pipelines (MetaShapedTexture *stex)
 {
   MetaShapedTexturePrivate *priv = stex->priv;
+  g_warning ("resetting pipelines!");
 
-  g_clear_pointer (&priv->base_pipeline, cogl_object_unref);
-  g_clear_pointer (&priv->masked_pipeline, cogl_object_unref);
-  g_clear_pointer (&priv->unblended_pipeline, cogl_object_unref);
+  cogl_clear_object (&priv->base_pipeline);
+  cogl_clear_object (&priv->masked_pipeline);
+  cogl_clear_object (&priv->unblended_pipeline);
 }
 
 static void
@@ -219,7 +220,7 @@ meta_shaped_texture_dispose (GObject *object)
     meta_texture_tower_free (priv->paint_tower);
   priv->paint_tower = NULL;
 
-  g_clear_pointer (&priv->texture, cogl_object_unref);
+  g_clear_object (&priv->texture);
   g_clear_pointer (&priv->opaque_region, cairo_region_destroy);
 
   meta_shaped_texture_set_mask_texture (self, NULL);
@@ -228,7 +229,7 @@ meta_shaped_texture_dispose (GObject *object)
 
   meta_shaped_texture_reset_pipelines (self);
 
-  g_clear_pointer (&priv->snippet, cogl_object_unref);
+  cogl_clear_object (&priv->snippet);
 
   G_OBJECT_CLASS (meta_shaped_texture_parent_class)->dispose (object);
 }
@@ -239,19 +240,20 @@ get_base_pipeline (MetaShapedTexture *stex,
 {
   MetaShapedTexturePrivate *priv = stex->priv;
   CoglPipeline *pipeline;
+  guint i = 0;
 
   if (priv->base_pipeline)
     return priv->base_pipeline;
 
   pipeline = cogl_pipeline_new (ctx);
-  cogl_pipeline_set_layer_wrap_mode_s (pipeline, 0,
-                                       COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE);
-  cogl_pipeline_set_layer_wrap_mode_t (pipeline, 0,
-                                       COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE);
-  cogl_pipeline_set_layer_wrap_mode_s (pipeline, 1,
-                                       COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE);
-  cogl_pipeline_set_layer_wrap_mode_t (pipeline, 1,
-                                       COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE);
+  for (i = 0; i < cogl_multi_plane_texture_get_n_planes (priv->texture); i++)
+    {
+      cogl_pipeline_set_layer_wrap_mode_s (pipeline, i,
+                                           COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE);
+      cogl_pipeline_set_layer_wrap_mode_t (pipeline, i,
+                                           COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE);
+    }
+
   if (!priv->is_y_inverted)
     {
       CoglMatrix matrix;
@@ -263,7 +265,10 @@ get_base_pipeline (MetaShapedTexture *stex,
     }
 
   if (priv->snippet)
-    cogl_pipeline_add_layer_snippet (pipeline, 0, priv->snippet);
+    {
+      for (i = 0; i < cogl_multi_plane_texture_get_n_planes (priv->texture); i++)
+        cogl_pipeline_add_layer_snippet (pipeline, i, priv->snippet);
+    }
 
   priv->base_pipeline = pipeline;
 
@@ -283,14 +288,19 @@ get_masked_pipeline (MetaShapedTexture *stex,
 {
   MetaShapedTexturePrivate *priv = stex->priv;
   CoglPipeline *pipeline;
+  gint i, n_layers = 0;
 
   if (priv->masked_pipeline)
     return priv->masked_pipeline;
 
   pipeline = cogl_pipeline_copy (get_base_pipeline (stex, ctx));
-  cogl_pipeline_set_layer_combine (pipeline, 1,
-                                   "RGBA = MODULATE (PREVIOUS, TEXTURE[A])",
-                                   NULL);
+  n_layers = cogl_multi_plane_texture_get_n_planes (pipeline);
+  for (i = 0; i < n_layers; i++)
+    {
+      cogl_pipeline_set_layer_combine (pipeline, i,
+                                       "RGBA = MODULATE (PREVIOUS, TEXTURE[A])",
+                                       NULL);
+    }
 
   priv->masked_pipeline = pipeline;
 
@@ -303,17 +313,15 @@ get_unblended_pipeline (MetaShapedTexture *stex,
 {
   MetaShapedTexturePrivate *priv = stex->priv;
   CoglPipeline *pipeline;
-  CoglColor color;
 
   if (priv->unblended_pipeline)
     return priv->unblended_pipeline;
 
   pipeline = cogl_pipeline_copy (get_base_pipeline (stex, ctx));
-  cogl_color_init_from_4ub (&color, 255, 255, 255, 255);
   cogl_pipeline_set_blend (pipeline,
                            "RGBA = ADD (SRC_COLOR, 0)",
                            NULL);
-  cogl_pipeline_set_color (pipeline, &color);
+  cogl_pipeline_set_color4ub (pipeline, 255, 255, 255, 255);
 
   priv->unblended_pipeline = pipeline;
 
@@ -350,8 +358,40 @@ paint_clipped_rectangle (CoglFramebuffer       *fb,
 }
 
 static void
-set_cogl_texture (MetaShapedTexture *stex,
-                  CoglTexture       *cogl_tex)
+check_texture_color_format (MetaShapedTexture *self,
+                            CoglMultiPlaneTexture *texture)
+{
+  CoglPixelFormat format = cogl_multi_plane_texture_get_format (texture);
+  static CoglSnippet *func1 = NULL, *func2 = NULL, *snippet3 = NULL;
+  guint n_layers = 0;
+
+    n_layers = cogl_pipeline_get_n_layers (self->priv->base_pipeline);
+
+    if (func1 != NULL)
+      return;
+
+    cogl_multi_plane_texture_create_color_conversion_snippets (texture,
+                                                               &func1,
+                                                               &func2,
+                                                               &snippet3);
+
+    /* Check if a snippet is actually necessary */
+    if (func1 != NULL)
+      {
+        cogl_pipeline_add_snippet (self->priv->base_pipeline, func1);
+        cogl_pipeline_add_snippet (self->priv->base_pipeline, func2);
+        meta_shaped_texture_set_create_mipmaps (self, FALSE);
+
+        cogl_pipeline_add_layer_snippet (self->priv->base_pipeline,
+                                         n_layers - 1,
+                                         snippet3);
+      }
+
+}
+
+static void
+set_planar_texture (MetaShapedTexture *stex,
+                    CoglMultiPlaneTexture *planar_tex)
 {
   MetaShapedTexturePrivate *priv;
   int width, height;
@@ -360,16 +400,14 @@ set_cogl_texture (MetaShapedTexture *stex,
 
   priv = stex->priv;
 
-  if (priv->texture)
-    cogl_object_unref (priv->texture);
+  cogl_clear_object (&priv->texture);
+  priv->texture = planar_tex;
 
-  priv->texture = cogl_tex;
-
-  if (cogl_tex != NULL)
+  if (planar_tex != NULL)
     {
-      cogl_object_ref (cogl_tex);
-      width = cogl_texture_get_width (COGL_TEXTURE (cogl_tex));
-      height = cogl_texture_get_height (COGL_TEXTURE (cogl_tex));
+      cogl_object_ref (planar_tex);
+      width = cogl_multi_plane_texture_get_width (planar_tex);
+      height = cogl_multi_plane_texture_get_height (planar_tex);
     }
   else
     {
@@ -377,6 +415,7 @@ set_cogl_texture (MetaShapedTexture *stex,
       height = 0;
     }
 
+  /* Do we have a different size? */
   if (priv->tex_width != width ||
       priv->tex_height != height)
     {
@@ -387,13 +426,24 @@ set_cogl_texture (MetaShapedTexture *stex,
       g_signal_emit (stex, signals[SIZE_CHANGED], 0);
     }
 
+  /* Check if we need to do color conversion to RGBA */
+  if (planar_tex != NULL && priv->base_pipeline != NULL)
+    {
+      check_texture_color_format (stex, planar_tex);
+    }
+
   /* NB: We don't queue a redraw of the actor here because we don't
    * know how much of the buffer has changed with respect to the
    * previous buffer. We only queue a redraw in response to surface
    * damage. */
 
-  if (priv->create_mipmaps)
-    meta_texture_tower_set_base_texture (priv->paint_tower, cogl_tex);
+  if (FALSE)
+  /* if (priv->create_mipmaps) */
+    {
+      /* XXX */
+      CoglTexture *cogl_tex = cogl_multi_plane_texture_get_plane (planar_tex, 0);
+      meta_texture_tower_set_base_texture (priv->paint_tower, cogl_tex);
+    }
 }
 
 static gboolean
@@ -426,13 +476,14 @@ meta_shaped_texture_paint (ClutterActor *actor)
   cairo_region_t *blended_tex_region;
   CoglContext *ctx;
   CoglFramebuffer *fb;
-  CoglTexture *paint_tex = NULL;
+  CoglMultiPlaneTexture *paint_tex = NULL;
+  guint n_planes;
   ClutterActorBox alloc;
   CoglPipelineFilter filter;
   gint64 now = g_get_monotonic_time ();
 
-  if (priv->clip_region && cairo_region_is_empty (priv->clip_region))
-    return;
+  /* if (priv->clip_region && cairo_region_is_empty (priv->clip_region)) */
+  /*   return; */
 
   if (!CLUTTER_ACTOR_IS_REALIZED (CLUTTER_ACTOR (stex)))
     clutter_actor_realize (CLUTTER_ACTOR (stex));
@@ -452,7 +503,8 @@ meta_shaped_texture_paint (ClutterActor *actor)
    * Setting the texture quality to high without SGIS_generate_mipmap
    * support for TFP textures will result in fallbacks to XGetImage.
    */
-  if (priv->create_mipmaps && priv->last_invalidation)
+  if (FALSE)
+  /* if (priv->create_mipmaps && priv->last_invalidation) */
     {
       gint64 age = now - priv->last_invalidation;
 
@@ -463,12 +515,13 @@ meta_shaped_texture_paint (ClutterActor *actor)
 
   if (paint_tex == NULL)
     {
-      paint_tex = COGL_TEXTURE (priv->texture);
+      paint_tex = priv->texture;
 
       if (paint_tex == NULL)
         return;
 
-      if (priv->create_mipmaps)
+      if (FALSE)
+      /* if (priv->create_mipmaps) */
         {
           /* Minus 1000 to ensure we don't fail the age test in timeout */
           priv->earliest_remipmap = now + MIN_MIPMAP_AGE_USEC - 1000;
@@ -481,6 +534,8 @@ meta_shaped_texture_paint (ClutterActor *actor)
         }
     }
 
+  n_planes = cogl_multi_plane_texture_get_n_planes (paint_tex);
+
   clutter_actor_get_scale (actor, &tex_scale, NULL);
   tex_width = priv->tex_width;
   tex_height = priv->tex_height;
@@ -585,8 +640,15 @@ meta_shaped_texture_paint (ClutterActor *actor)
       if (!cairo_region_is_empty (region))
         {
           opaque_pipeline = get_unblended_pipeline (stex, ctx);
-          cogl_pipeline_set_layer_texture (opaque_pipeline, 0, paint_tex);
-          cogl_pipeline_set_layer_filters (opaque_pipeline, 0, filter, filter);
+
+          for (i = 0; i < n_planes; i++)
+            {
+              CoglTexture *plane = cogl_multi_plane_texture_get_plane (paint_tex, i);
+
+
+              cogl_pipeline_set_layer_texture (opaque_pipeline, i, plane);
+              cogl_pipeline_set_layer_filters (opaque_pipeline, i, filter, filter);
+            }
 
           n_rects = cairo_region_num_rectangles (region);
           for (i = 0; i < n_rects; i++)
@@ -613,6 +675,7 @@ meta_shaped_texture_paint (ClutterActor *actor)
   if (!blended_tex_region || !cairo_region_is_empty (blended_tex_region))
     {
       CoglPipeline *blended_pipeline;
+      guint i;
 
       if (priv->mask_texture == NULL)
         {
@@ -621,16 +684,21 @@ meta_shaped_texture_paint (ClutterActor *actor)
       else
         {
           blended_pipeline = get_masked_pipeline (stex, ctx);
-          cogl_pipeline_set_layer_texture (blended_pipeline, 1, priv->mask_texture);
-          cogl_pipeline_set_layer_filters (blended_pipeline, 1, filter, filter);
+          cogl_pipeline_set_layer_texture (blended_pipeline, n_planes, priv->mask_texture);
+          cogl_pipeline_set_layer_filters (blended_pipeline, n_planes, filter, filter);
         }
 
-      cogl_pipeline_set_layer_texture (blended_pipeline, 0, paint_tex);
-      cogl_pipeline_set_layer_filters (blended_pipeline, 0, filter, filter);
+      for (i = 0; i < n_planes; i++)
+        {
+          CoglTexture *plane = cogl_multi_plane_texture_get_plane (paint_tex, i);
+          g_warning ("Blended pipeline: adding layer %d, %p", i, plane);
+
+          cogl_pipeline_set_layer_texture (blended_pipeline, i, plane);
+          cogl_pipeline_set_layer_filters (blended_pipeline, i, filter, filter);
+        }
 
-      CoglColor color;
-      cogl_color_init_from_4ub (&color, opacity, opacity, opacity, opacity);
-      cogl_pipeline_set_color (blended_pipeline, &color);
+      cogl_pipeline_set_color4ub (blended_pipeline,
+                                  opacity, opacity, opacity, opacity);
 
       if (blended_tex_region)
         {
@@ -861,15 +929,15 @@ meta_shaped_texture_update_area (MetaShapedTexture *stex,
 /**
  * meta_shaped_texture_set_texture:
  * @stex: The #MetaShapedTexture
- * @pixmap: The #CoglTexture to display
+ * @pixmap: The #CoglMultiPlaneTexture to display
  */
 void
 meta_shaped_texture_set_texture (MetaShapedTexture *stex,
-                                 CoglTexture       *texture)
+                                 CoglMultiPlaneTexture *texture)
 {
   g_return_if_fail (META_IS_SHAPED_TEXTURE (stex));
 
-  set_cogl_texture (stex, texture);
+  set_planar_texture (stex, texture);
 }
 
 /**
@@ -903,7 +971,7 @@ meta_shaped_texture_set_snippet (MetaShapedTexture *stex,
 
   meta_shaped_texture_reset_pipelines (stex);
 
-  g_clear_pointer (&priv->snippet, cogl_object_unref);
+  cogl_clear_object (&priv->snippet);
   if (snippet)
     priv->snippet = cogl_object_ref (snippet);
 }
@@ -918,7 +986,8 @@ CoglTexture *
 meta_shaped_texture_get_texture (MetaShapedTexture *stex)
 {
   g_return_val_if_fail (META_IS_SHAPED_TEXTURE (stex), NULL);
-  return COGL_TEXTURE (stex->priv->texture);
+
+  return cogl_multi_plane_texture_get_plane (stex->priv->texture, 0);
 }
 
 /**
@@ -976,19 +1045,19 @@ cairo_surface_t *
 meta_shaped_texture_get_image (MetaShapedTexture     *stex,
                                cairo_rectangle_int_t *clip)
 {
-  CoglTexture *texture, *mask_texture;
+  CoglMultiPlaneTexture *texture, *mask_texture;
   cairo_rectangle_int_t texture_rect = { 0, 0, 0, 0 };
   cairo_surface_t *surface;
 
   g_return_val_if_fail (META_IS_SHAPED_TEXTURE (stex), NULL);
 
-  texture = COGL_TEXTURE (stex->priv->texture);
+  texture = stex->priv->texture;
 
   if (texture == NULL)
     return NULL;
 
-  texture_rect.width = cogl_texture_get_width (texture);
-  texture_rect.height = cogl_texture_get_height (texture);
+  texture_rect.width = cogl_multi_plane_texture_get_width (texture);
+  texture_rect.height = cogl_multi_plane_texture_get_height (texture);
 
   if (clip != NULL)
     {
@@ -998,6 +1067,7 @@ meta_shaped_texture_get_image (MetaShapedTexture     *stex,
         return NULL;
     }
 
+  /* XXX */
   if (clip != NULL)
     texture = cogl_texture_new_from_sub_texture (texture,
                                                  clip->x,
@@ -1006,9 +1076,10 @@ meta_shaped_texture_get_image (MetaShapedTexture     *stex,
                                                  clip->height);
 
   surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
-                                        cogl_texture_get_width (texture),
-                                        cogl_texture_get_height (texture));
+                                        cogl_multi_plane_texture_get_width (texture),
+                                        cogl_multi_plane_texture_get_height (texture));
 
+  /* XXX */
   cogl_texture_get_data (texture, CLUTTER_CAIRO_FORMAT_ARGB32,
                          cairo_image_surface_get_stride (surface),
                          cairo_image_surface_get_data (surface));
@@ -1016,7 +1087,7 @@ meta_shaped_texture_get_image (MetaShapedTexture     *stex,
   cairo_surface_mark_dirty (surface);
 
   if (clip != NULL)
-    cogl_object_unref (texture);
+    g_object_unref (texture);
 
   mask_texture = stex->priv->mask_texture;
   if (mask_texture != NULL)
@@ -1032,8 +1103,8 @@ meta_shaped_texture_get_image (MetaShapedTexture     *stex,
                                                           clip->height);
 
       mask_surface = cairo_image_surface_create (CAIRO_FORMAT_A8,
-                                                 cogl_texture_get_width (mask_texture),
-                                                 cogl_texture_get_height (mask_texture));
+                                                 cogl_multi_plane_texture_get_width (mask_texture),
+                                                 cogl_multi_plane_texture_get_height (mask_texture));
 
       cogl_texture_get_data (mask_texture, COGL_PIXEL_FORMAT_A_8,
                              cairo_image_surface_get_stride (mask_surface),
@@ -1107,5 +1178,6 @@ cullable_iface_init (MetaCullableInterface *iface)
 ClutterActor *
 meta_shaped_texture_new (void)
 {
+    g_warning ("New MetaShapedTexture!");
   return g_object_new (META_TYPE_SHAPED_TEXTURE, NULL);
 }
diff --git a/src/compositor/meta-surface-actor-x11.c b/src/compositor/meta-surface-actor-x11.c
index 1f897be3f..2d6c4e571 100644
--- a/src/compositor/meta-surface-actor-x11.c
+++ b/src/compositor/meta-surface-actor-x11.c
@@ -43,7 +43,7 @@ struct _MetaSurfaceActorX11Private
 
   MetaDisplay *display;
 
-  CoglTexture *texture;
+  CoglMultiPlaneTexture *texture;
   Pixmap pixmap;
   Damage damage;
 
@@ -130,8 +130,9 @@ set_pixmap (MetaSurfaceActorX11 *self,
   else if (G_UNLIKELY (!cogl_texture_pixmap_x11_is_using_tfp_extension (COGL_TEXTURE_PIXMAP_X11 (texture))))
     g_warning ("NOTE: Not using GLX TFP!\n");
 
-  priv->texture = texture;
-  meta_shaped_texture_set_texture (stex, texture);
+  /* FIXME: we need to find out the format here */
+  priv->texture = cogl_multi_plane_texture_new_single_plane (COGL_PIXEL_FORMAT_ANY, texture);
+  meta_shaped_texture_set_texture (stex, priv->texture);
 }
 
 static void
@@ -191,6 +192,7 @@ meta_surface_actor_x11_process_damage (MetaSurfaceActor *actor,
 {
   MetaSurfaceActorX11 *self = META_SURFACE_ACTOR_X11 (actor);
   MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self);
+  CoglTexture *texture;
 
   priv->received_damage = TRUE;
 
@@ -214,7 +216,8 @@ meta_surface_actor_x11_process_damage (MetaSurfaceActor *actor,
   if (!is_visible (self))
     return;
 
-  cogl_texture_pixmap_x11_update_area (COGL_TEXTURE_PIXMAP_X11 (priv->texture),
+  texture = cogl_multi_plane_texture_get_plane (priv->texture, 0);
+  cogl_texture_pixmap_x11_update_area (COGL_TEXTURE_PIXMAP_X11 (texture),
                                        x, y, width, height);
 }
 
diff --git a/src/wayland/meta-wayland-buffer.c b/src/wayland/meta-wayland-buffer.c
index 9fee02d52..263826151 100644
--- a/src/wayland/meta-wayland-buffer.c
+++ b/src/wayland/meta-wayland-buffer.c
@@ -165,6 +165,7 @@ shm_buffer_get_cogl_pixel_format (struct wl_shm_buffer  *shm_buffer,
   CoglPixelFormat format;
   CoglTextureComponents components = COGL_TEXTURE_COMPONENTS_RGBA;
 
+  g_warning ("SHM BUFFER_FORMAT: %d", wl_shm_buffer_get_format (shm_buffer));
   switch (wl_shm_buffer_get_format (shm_buffer))
     {
 #if G_BYTE_ORDER == G_BIG_ENDIAN
@@ -184,6 +185,26 @@ shm_buffer_get_cogl_pixel_format (struct wl_shm_buffer  *shm_buffer,
       components = COGL_TEXTURE_COMPONENTS_RGB;
       break;
 #endif
+    case WL_SHM_FORMAT_NV12:
+      format = COGL_PIXEL_FORMAT_NV12;
+      g_warning ("FORMAT IS NV12");
+      break;
+    case WL_SHM_FORMAT_NV21:
+      g_warning ("FORMAT IS NV21");
+      break;
+    case WL_SHM_FORMAT_YUV422:
+      g_warning ("FORMAT IS YUV422");
+      break;
+    case WL_SHM_FORMAT_YVU422:
+      g_warning ("FORMAT IS YVU422");
+      break;
+    case WL_SHM_FORMAT_YUV444:
+      g_warning ("FORMAT IS YUV444");
+      break;
+    case WL_SHM_FORMAT_YVU444:
+      g_warning ("FORMAT IS YVU444");
+      break;
+
     default:
       g_warn_if_reached ();
       format = COGL_PIXEL_FORMAT_ARGB_8888;
@@ -206,44 +227,80 @@ shm_buffer_attach (MetaWaylandBuffer *buffer,
   int stride, width, height;
   CoglPixelFormat format;
   CoglTextureComponents components;
-  CoglBitmap *bitmap;
-  CoglTexture *texture;
+  guint i, n_planes;
+  guint h_factors[3], v_factors[3];
+  gsize offset = 0;
+  const guint8 *data;
+  GPtrArray *planes;
+  gboolean ret;
 
   if (buffer->texture)
     return TRUE;
 
+  /* Query the necessary parameters */
   shm_buffer = wl_shm_buffer_get (buffer->resource);
   stride = wl_shm_buffer_get_stride (shm_buffer);
   width = wl_shm_buffer_get_width (shm_buffer);
   height = wl_shm_buffer_get_height (shm_buffer);
 
-  wl_shm_buffer_begin_access (shm_buffer);
-
   shm_buffer_get_cogl_pixel_format (shm_buffer, &format, &components);
+  n_planes = cogl_pixel_format_get_n_planes (format);
+  cogl_pixel_format_get_subsampling_factors (format, h_factors,  v_factors);
 
-  bitmap = cogl_bitmap_new_for_data (cogl_context,
-                                     width, height,
-                                     format,
-                                     stride,
-                                     wl_shm_buffer_get_data (shm_buffer));
+  /* Safely access the data inside the buffer */
+  wl_shm_buffer_begin_access (shm_buffer);
+  data = wl_shm_buffer_get_data (shm_buffer);
 
-  texture = COGL_TEXTURE (cogl_texture_2d_new_from_bitmap (bitmap));
-  cogl_texture_set_components (COGL_TEXTURE (texture), components);
+  planes = g_ptr_array_new_full (n_planes, cogl_object_unref);
+  for (i = 0; i < n_planes; i++)
+    {
+      CoglBitmap *bitmap;
+      CoglTexture *plane;
+
+      /* Internally, the texture's planes are laid out in memory as one
+       * contiguous block, so we have to consider any subsampling (based on the
+       * pixel format). */
+      if (i == 0)
+        offset = 0;
+      else
+        offset += (stride / h_factors[i-1]) * (height / v_factors[i-1]);
+
+      bitmap = cogl_bitmap_new_for_data (cogl_context,
+                                         width / h_factors[i],
+                                         height / v_factors[i],
+                                         format,
+                                         stride, /* XXX Do we need to change this too?*/
+                                         data + offset);
+      g_assert (bitmap);
+
+      plane = COGL_TEXTURE (cogl_texture_2d_new_from_bitmap (bitmap));
+      cogl_texture_set_components (COGL_TEXTURE (plane), components);
+
+      cogl_object_unref (bitmap);
+
+      if (G_UNLIKELY (!cogl_texture_allocate (COGL_TEXTURE (plane), error)))
+        {
+          g_clear_pointer (&plane, cogl_object_unref);
+          ret = FALSE;
+          goto out;
+        }
 
-  cogl_object_unref (bitmap);
+      g_ptr_array_add (planes, plane);
+    }
 
-  if (!cogl_texture_allocate (COGL_TEXTURE (texture), error))
-    g_clear_pointer (&texture, cogl_object_unref);
+  buffer->texture = cogl_multi_plane_texture_new (format,
+                                             g_ptr_array_free (planes, FALSE),
+                                             n_planes);
+  buffer->is_y_inverted = TRUE;
+  ret = TRUE;
 
+out:
   wl_shm_buffer_end_access (shm_buffer);
 
-  buffer->texture = texture;
-  buffer->is_y_inverted = TRUE;
-
-  if (!buffer->texture)
-    return FALSE;
+  if (!ret)
+    g_ptr_array_free (planes, TRUE);
 
-  return TRUE;
+  return ret;
 }
 
 static gboolean
@@ -257,12 +314,15 @@ egl_image_buffer_attach (MetaWaylandBuffer *buffer,
   EGLDisplay egl_display = cogl_egl_context_get_egl_display (cogl_context);
   int format, width, height, y_inverted;
   CoglPixelFormat cogl_format;
-  EGLImageKHR egl_image;
-  CoglTexture2D *texture;
+  guint i, n_planes;
+  GPtrArray *planes;
+  gboolean ret = FALSE;
+  EGLint attrib_list[3] = { EGL_NONE, EGL_NONE, EGL_NONE };
 
   if (buffer->texture)
     return TRUE;
 
+  /* Query the necessary properties */
   if (!meta_egl_query_wayland_buffer (egl, egl_display, buffer->resource,
                                       EGL_TEXTURE_FORMAT, &format,
                                       error))
@@ -283,6 +343,7 @@ egl_image_buffer_attach (MetaWaylandBuffer *buffer,
                                       NULL))
     y_inverted = EGL_TRUE;
 
+  /* Map the EGL texture format to CoglPixelFormat, if possible */
   switch (format)
     {
     case EGL_TEXTURE_RGB:
@@ -291,6 +352,14 @@ egl_image_buffer_attach (MetaWaylandBuffer *buffer,
     case EGL_TEXTURE_RGBA:
       cogl_format = COGL_PIXEL_FORMAT_RGBA_8888_PRE;
       break;
+    case EGL_TEXTURE_Y_UV_WL:
+      g_warning ("Got a NV12 color format texture!!");
+      cogl_format = COGL_PIXEL_FORMAT_NV12;
+      break;
+    case EGL_TEXTURE_Y_U_V_WL:
+      g_warning ("Got a YUV 4:4:4 color format texture!!");
+      cogl_format = COGL_PIXEL_FORMAT_YUV444;
+      break;
     default:
       g_set_error (error, G_IO_ERROR,
                    G_IO_ERROR_FAILED,
@@ -298,30 +367,56 @@ egl_image_buffer_attach (MetaWaylandBuffer *buffer,
       return FALSE;
     }
 
-  /* The WL_bind_wayland_display spec states that EGL_NO_CONTEXT is to be used
-   * in conjunction with the EGL_WAYLAND_BUFFER_WL target. */
-  egl_image = meta_egl_create_image (egl, egl_display, EGL_NO_CONTEXT,
-                                     EGL_WAYLAND_BUFFER_WL, buffer->resource,
-                                     NULL,
-                                     error);
-  if (egl_image == EGL_NO_IMAGE_KHR)
-    return FALSE;
+  n_planes = cogl_pixel_format_get_n_planes (cogl_format);
+  planes = g_ptr_array_new_full (n_planes, cogl_object_unref);
 
-  texture = cogl_egl_texture_2d_new_from_image (cogl_context,
-                                                width, height,
-                                                cogl_format,
-                                                egl_image,
-                                                error);
+  /* Each EGLImage is a plane in the final texture */
+  for (i = 0; i < n_planes; i++)
+    {
+      EGLImageKHR egl_img;
+      CoglTexture2D *texture;
 
-  meta_egl_destroy_image (egl, egl_display, egl_image, NULL);
+      /* Specify that we want the i'th plane */
+      attrib_list[0] = EGL_WAYLAND_PLANE_WL;
+      attrib_list[1] = i;
 
-  if (!texture)
-    return FALSE;
+      /* The WL_bind_wayland_display spec states that EGL_NO_CONTEXT is to be
+       * used in conjunction with the EGL_WAYLAND_BUFFER_WL target. */
+      egl_img = meta_egl_create_image (egl, egl_display, EGL_NO_CONTEXT,
+                                       EGL_WAYLAND_BUFFER_WL, buffer->resource,
+                                       attrib_list,
+                                       error);
+
+      if (G_UNLIKELY (egl_img == EGL_NO_IMAGE_KHR))
+        goto out;
+
+      texture = cogl_egl_texture_2d_new_from_image (cogl_context,
+                                                    width, height,
+                                                    cogl_format,
+                                                    egl_img,
+                                                    error);
 
-  buffer->texture = COGL_TEXTURE (texture);
+      meta_egl_destroy_image (egl, egl_display, egl_img, NULL);
+
+      if (G_UNLIKELY (!texture))
+        goto out;
+
+      g_ptr_array_add (planes, texture);
+    }
+
+
+  buffer->texture = cogl_multi_plane_texture_new (cogl_format,
+                                             g_ptr_array_free (planes, FALSE),
+                                             n_planes);
   buffer->is_y_inverted = !!y_inverted;
 
-  return TRUE;
+  ret = TRUE;
+
+out:
+  if (!ret)
+    g_ptr_array_free (planes, TRUE);
+
+  return ret;
 }
 
 #ifdef HAVE_WAYLAND_EGLSTREAM
@@ -358,14 +453,18 @@ meta_wayland_buffer_attach (MetaWaylandBuffer *buffer,
   switch (buffer->type)
     {
     case META_WAYLAND_BUFFER_TYPE_SHM:
+      g_warning ("GOT SHM BUFFER");
       return shm_buffer_attach (buffer, error);
     case META_WAYLAND_BUFFER_TYPE_EGL_IMAGE:
+      g_warning ("GOT EGL IMAGE BUFFER");
       return egl_image_buffer_attach (buffer, error);
 #ifdef HAVE_WAYLAND_EGLSTREAM
     case META_WAYLAND_BUFFER_TYPE_EGL_STREAM:
+      g_warning ("GOT EGL STREAM BUFFER");
       return egl_stream_buffer_attach (buffer, error);
 #endif
     case META_WAYLAND_BUFFER_TYPE_DMA_BUF:
+      g_warning ("GOT DMA BUF BUFFER");
       return meta_wayland_dma_buf_buffer_attach (buffer, error);
     case META_WAYLAND_BUFFER_TYPE_UNKNOWN:
       g_assert_not_reached ();
@@ -375,7 +474,7 @@ meta_wayland_buffer_attach (MetaWaylandBuffer *buffer,
   g_assert_not_reached ();
 }
 
-CoglTexture *
+CoglMultiPlaneTexture *
 meta_wayland_buffer_get_texture (MetaWaylandBuffer *buffer)
 {
   return buffer->texture;
@@ -419,27 +518,35 @@ process_shm_buffer_damage (MetaWaylandBuffer *buffer,
       const uint8_t *data = wl_shm_buffer_get_data (shm_buffer);
       int32_t stride = wl_shm_buffer_get_stride (shm_buffer);
       CoglPixelFormat format;
+      guint n_planes;
       int bpp;
       cairo_rectangle_int_t rect;
 
       shm_buffer_get_cogl_pixel_format (shm_buffer, &format, NULL);
+      /* XXX */
       bpp = _cogl_pixel_format_get_bytes_per_pixel (format);
       cairo_region_get_rectangle (region, i, &rect);
 
-      if (!_cogl_texture_set_region (buffer->texture,
-                                     rect.width, rect.height,
-                                     format,
-                                     stride,
-                                     data + rect.x * bpp + rect.y * stride,
-                                     rect.x, rect.y,
-                                     0,
-                                     error))
+      for (i = 0; i < cogl_multi_plane_texture_get_n_planes (buffer->texture); i++)
         {
-          set_texture_failed = TRUE;
-          break;
+          CoglTexture *plane = cogl_multi_plane_texture_get_plane (buffer->texture, i);
+
+          if (!_cogl_texture_set_region (plane,
+                                         rect.width, rect.height,
+                                         format,
+                                         stride,
+                                         data + rect.x * bpp + rect.y * stride,
+                                         rect.x, rect.y,
+                                         0,
+                                         error))
+            {
+              set_texture_failed = TRUE;
+              goto out;
+            }
         }
     }
 
+out:
   wl_shm_buffer_end_access (shm_buffer);
 
   return !set_texture_failed;
@@ -486,7 +593,7 @@ meta_wayland_buffer_finalize (GObject *object)
 {
   MetaWaylandBuffer *buffer = META_WAYLAND_BUFFER (object);
 
-  g_clear_pointer (&buffer->texture, cogl_object_unref);
+  cogl_clear_object (&buffer->texture);
 #ifdef HAVE_WAYLAND_EGLSTREAM
   g_clear_object (&buffer->egl_stream.stream);
 #endif
diff --git a/src/wayland/meta-wayland-buffer.h b/src/wayland/meta-wayland-buffer.h
index 3709c85ff..165c9dfb8 100644
--- a/src/wayland/meta-wayland-buffer.h
+++ b/src/wayland/meta-wayland-buffer.h
@@ -51,7 +51,7 @@ struct _MetaWaylandBuffer
   struct wl_resource *resource;
   struct wl_listener destroy_listener;
 
-  CoglTexture *texture;
+  CoglMultiPlaneTexture *texture;
   gboolean is_y_inverted;
 
   MetaWaylandBufferType type;
@@ -77,7 +77,7 @@ gboolean                meta_wayland_buffer_is_realized         (MetaWaylandBuff
 gboolean                meta_wayland_buffer_realize             (MetaWaylandBuffer     *buffer);
 gboolean                meta_wayland_buffer_attach              (MetaWaylandBuffer     *buffer,
                                                                  GError               **error);
-CoglTexture *           meta_wayland_buffer_get_texture         (MetaWaylandBuffer     *buffer);
+CoglMultiPlaneTexture * meta_wayland_buffer_get_texture         (MetaWaylandBuffer     *buffer);
 CoglSnippet *           meta_wayland_buffer_create_snippet      (MetaWaylandBuffer     *buffer);
 gboolean                meta_wayland_buffer_is_y_inverted       (MetaWaylandBuffer     *buffer);
 void                    meta_wayland_buffer_process_damage      (MetaWaylandBuffer     *buffer,
diff --git a/src/wayland/meta-wayland-cursor-surface.c b/src/wayland/meta-wayland-cursor-surface.c
index 92f86c9ec..c0e2c55e6 100644
--- a/src/wayland/meta-wayland-cursor-surface.c
+++ b/src/wayland/meta-wayland-cursor-surface.c
@@ -67,8 +67,13 @@ update_cursor_sprite_texture (MetaWaylandCursorSurface *cursor_surface)
 
   if (buffer)
     {
+      CoglTexture *texture;
+
+      /* We assume that we get a simple (single-plane) texture here */
+      texture = cogl_multi_plane_texture_get_plane (buffer->texture, 0);
+
       meta_cursor_sprite_set_texture (cursor_sprite,
-                                      buffer->texture,
+                                      texture,
                                       priv->hot_x * surface->scale,
                                       priv->hot_y * surface->scale);
     }
diff --git a/src/wayland/meta-wayland-dma-buf.c b/src/wayland/meta-wayland-dma-buf.c
index 347da2484..d52678c19 100644
--- a/src/wayland/meta-wayland-dma-buf.c
+++ b/src/wayland/meta-wayland-dma-buf.c
@@ -78,6 +78,7 @@ meta_wayland_dma_buf_buffer_attach (MetaWaylandBuffer *buffer,
   CoglPixelFormat cogl_format;
   EGLImageKHR egl_image;
   CoglTexture2D *texture;
+  CoglTexture **textures;
   EGLint attribs[64];
   int attr_idx = 0;
 
@@ -196,7 +197,9 @@ meta_wayland_dma_buf_buffer_attach (MetaWaylandBuffer *buffer,
   if (!texture)
     return FALSE;
 
-  buffer->texture = COGL_TEXTURE (texture);
+  textures = g_new (CoglTexture *, 1);
+  textures[0] = COGL_TEXTURE (texture);
+  buffer->texture = cogl_multi_plane_texture_new (cogl_format, textures, 1);
   buffer->is_y_inverted = dma_buf->is_y_inverted;
 
   return TRUE;
diff --git a/src/wayland/meta-wayland-shell-surface.c b/src/wayland/meta-wayland-shell-surface.c
index 50dbb9bcd..a5184d0c0 100644
--- a/src/wayland/meta-wayland-shell-surface.c
+++ b/src/wayland/meta-wayland-shell-surface.c
@@ -153,7 +153,7 @@ meta_wayland_shell_surface_surface_commit (MetaWaylandSurfaceRole  *surface_role
   MetaWaylandSurfaceRoleClass *surface_role_class;
   MetaWindow *window;
   MetaWaylandBuffer *buffer;
-  CoglTexture *texture;
+  CoglMultiPlaneTexture *texture;
   double scale;
 
   surface_role_class =
@@ -171,8 +171,8 @@ meta_wayland_shell_surface_surface_commit (MetaWaylandSurfaceRole  *surface_role
   scale = meta_wayland_actor_surface_calculate_scale (actor_surface);
   texture = meta_wayland_buffer_get_texture (buffer);
 
-  window->buffer_rect.width = cogl_texture_get_width (texture) * scale;
-  window->buffer_rect.height = cogl_texture_get_height (texture) * scale;
+  window->buffer_rect.width = cogl_multi_plane_texture_get_width (texture) * scale;
+  window->buffer_rect.height = cogl_multi_plane_texture_get_height (texture) * scale;
 }
 
 static void
diff --git a/src/wayland/meta-wayland-surface.c b/src/wayland/meta-wayland-surface.c
index b918e296e..0f8d6484e 100644
--- a/src/wayland/meta-wayland-surface.c
+++ b/src/wayland/meta-wayland-surface.c
@@ -648,7 +648,7 @@ meta_wayland_surface_apply_pending_state (MetaWaylandSurface      *surface,
           if (switched_buffer && meta_wayland_surface_get_actor (surface))
             {
               MetaShapedTexture *stex;
-              CoglTexture *texture;
+              CoglMultiPlaneTexture *texture;
               CoglSnippet *snippet;
               gboolean is_y_inverted;
 
@@ -1749,8 +1749,8 @@ meta_wayland_surface_get_width (MetaWaylandSurface *surface)
   buffer = surface->buffer_ref.buffer;
   if (buffer)
     {
-      CoglTexture *texture = meta_wayland_buffer_get_texture (buffer);
-      return cogl_texture_get_width (texture) / surface->scale;
+      CoglMultiPlaneTexture *texture = meta_wayland_buffer_get_texture (buffer);
+      return cogl_multi_plane_texture_get_width (texture) / surface->scale;
     }
   else
     {
@@ -1766,8 +1766,8 @@ meta_wayland_surface_get_height (MetaWaylandSurface *surface)
   buffer = surface->buffer_ref.buffer;
   if (buffer)
     {
-      CoglTexture *texture = meta_wayland_buffer_get_texture (buffer);
-      return cogl_texture_get_height (texture) / surface->scale;
+      CoglMultiPlaneTexture *texture = meta_wayland_buffer_get_texture (buffer);
+      return cogl_multi_plane_texture_get_height (texture) / surface->scale;
     }
   else
     {
diff --git a/src/wayland/meta-wayland.c b/src/wayland/meta-wayland.c
index 25b49918f..d2436d6b6 100644
--- a/src/wayland/meta-wayland.c
+++ b/src/wayland/meta-wayland.c
@@ -311,6 +311,23 @@ meta_wayland_compositor_init (MetaWaylandCompositor *compositor)
   compositor->scheduled_surface_associations = g_hash_table_new (NULL, NULL);
 }
 
+static void
+add_supported_shm_formats (struct wl_display *display)
+{
+  guint i;
+
+  /* Note that a Wayland compositor should support WL_SHM_FORMAT_ARGB8888 and
+   * WL_SHM_FORMAT_XRGB8888 by default, so no need to add it here. */
+  static const guint32 SUPPORTED_FORMATS[] = {
+    WL_SHM_FORMAT_NV12
+  };
+
+  for (i = 0; i < G_N_ELEMENTS (SUPPORTED_FORMATS); i++)
+    {
+      wl_display_add_shm_format (display, SUPPORTED_FORMATS[i]);
+    }
+}
+
 void
 meta_wayland_pre_clutter_init (void)
 {
@@ -325,6 +342,8 @@ meta_wayland_pre_clutter_init (void)
     g_error ("Failed to create the global wl_display");
 
   clutter_wayland_set_compositor_display (compositor->wayland_display);
+
+  add_supported_shm_formats (compositor->wayland_display);
 }
 
 static bool


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]