[mutter/wip/nielsdg/add-yuv-support: 3/5] cogl: Add non-RGBA pixel formats



commit a225a8d247e4d625d446d9cf9b58721a85de9eaa
Author: Niels De Graef <niels degraef barco com>
Date:   Wed Jun 19 08:41:44 2019 +0200

    cogl: Add non-RGBA pixel formats
    
    Up until now, we didn't support any YUV pixel formats. This was for
    several reasons: first, we draw onto an RGBA framebuffer, so any
    YUV-based color format needs to be converted to RGBA using a shader.
    
    Next, some more complex pixel format have extra properties that we have
    not had to deal with right now: they can be located on multiple "planes"
    (which means components are not combined in a single texture or memory
    block). Some pixel formats also have a notion of "subsampling", where
    one does not save a component for each and every pixel, but rather for
    every other pixel (possibly in both the horizontal and vertical sense).
    
    To deal with this, we introduce a new type as well:
    `CoglPixelFormatConversion` provides a wrapper for the necessary shaders
    (which in Cogl are represented by `CoglSnippet`s).

 cogl/cogl/cogl-atlas-texture.c                     |   4 +-
 cogl/cogl/cogl-atlas.c                             |   6 +-
 cogl/cogl/cogl-bitmap-conversion.c                 |  30 +
 cogl/cogl/cogl-bitmap-packing.h                    |  60 ++
 cogl/cogl/cogl-bitmap.c                            |   8 +-
 cogl/cogl/cogl-blit.c                              |   2 +-
 cogl/cogl/cogl-framebuffer.c                       |   2 +-
 cogl/cogl/cogl-pixel-format-conversion.c           | 182 ++++++
 cogl/cogl/cogl-pixel-format-conversion.h           |  92 +++
 cogl/cogl/cogl-pixel-format.c                      | 688 ++++++++++++++++++---
 cogl/cogl/cogl-pixel-format.h                      | 134 +++-
 cogl/cogl/cogl-texture-2d-sliced.c                 |   6 +-
 cogl/cogl/cogl-texture-2d.c                        |   2 +-
 cogl/cogl/cogl-texture.c                           |  14 +-
 cogl/cogl/cogl.c                                   |   2 +-
 cogl/cogl/deprecated/cogl-auto-texture.c           |   2 +-
 cogl/cogl/driver/gl/cogl-framebuffer-gl.c          |   4 +-
 cogl/cogl/driver/gl/cogl-texture-2d-gl.c           |   8 +-
 cogl/cogl/driver/gl/gl/cogl-driver-gl.c            |  30 +
 cogl/cogl/driver/gl/gl/cogl-texture-driver-gl.c    |   4 +-
 cogl/cogl/driver/gl/gles/cogl-driver-gles.c        |  30 +
 .../cogl/driver/gl/gles/cogl-texture-driver-gles.c |   6 +-
 cogl/cogl/libmutter-cogl.map.in                    |   1 -
 cogl/cogl/meson.build                              |   6 +-
 cogl/cogl/winsys/cogl-texture-pixmap-x11.c         |   2 +-
 src/wayland/meta-wayland-buffer.c                  |   2 +-
 26 files changed, 1195 insertions(+), 132 deletions(-)
---
diff --git a/cogl/cogl/cogl-atlas-texture.c b/cogl/cogl/cogl-atlas-texture.c
index e7f9c2125..5bb6bdfc4 100644
--- a/cogl/cogl/cogl-atlas-texture.c
+++ b/cogl/cogl/cogl-atlas-texture.c
@@ -937,12 +937,12 @@ cogl_atlas_texture_new_from_data (CoglContext *ctx,
   CoglBitmap *bmp;
   CoglAtlasTexture *atlas_tex;
 
-  g_return_val_if_fail (format != COGL_PIXEL_FORMAT_ANY, NULL);
+  g_return_val_if_fail (cogl_pixel_format_get_n_planes (format) == 1, NULL);
   g_return_val_if_fail (data != NULL, NULL);
 
   /* Rowstride from width if not given */
   if (rowstride == 0)
-    rowstride = width * _cogl_pixel_format_get_bytes_per_pixel (format);
+    rowstride = width * cogl_pixel_format_get_bytes_per_pixel_simple (format);
 
   /* Wrap the data into a bitmap */
   bmp = cogl_bitmap_new_for_data (ctx,
diff --git a/cogl/cogl/cogl-atlas.c b/cogl/cogl/cogl-atlas.c
index 8bcb491bc..6e1cdc65f 100644
--- a/cogl/cogl/cogl-atlas.c
+++ b/cogl/cogl/cogl-atlas.c
@@ -193,7 +193,7 @@ _cogl_atlas_get_initial_size (CoglPixelFormat format,
      initial minimum size. If the format is only 1 byte per pixel we
      can use 1024x1024, otherwise we'll assume it will take 4 bytes
      per pixel and use 512x512. */
-  if (_cogl_pixel_format_get_bytes_per_pixel (format) == 1)
+  if (cogl_pixel_format_get_bytes_per_pixel_simple (format) == 1)
     size = 1024;
   else
     size = 512;
@@ -291,7 +291,9 @@ _cogl_atlas_create_texture (CoglAtlas *atlas,
     {
       uint8_t *clear_data;
       CoglBitmap *clear_bmp;
-      int bpp = _cogl_pixel_format_get_bytes_per_pixel (atlas->texture_format);
+      int bpp;
+
+      bpp = cogl_pixel_format_get_bytes_per_pixel_simple (atlas->texture_format);
 
       /* Create a buffer of zeroes to initially clear the texture */
       clear_data = g_malloc0 (width * height * bpp);
diff --git a/cogl/cogl/cogl-bitmap-conversion.c b/cogl/cogl/cogl-bitmap-conversion.c
index b3ebf8773..2930119ec 100644
--- a/cogl/cogl/cogl-bitmap-conversion.c
+++ b/cogl/cogl/cogl-bitmap-conversion.c
@@ -320,7 +320,37 @@ _cogl_bitmap_needs_short_temp_buffer (CoglPixelFormat format)
     case COGL_PIXEL_FORMAT_DEPTH_32:
     case COGL_PIXEL_FORMAT_DEPTH_24_STENCIL_8:
     case COGL_PIXEL_FORMAT_ANY:
+    /* No support for YUV or multi-plane formats */
     case COGL_PIXEL_FORMAT_YUV:
+    case COGL_PIXEL_FORMAT_YUYV:
+    case COGL_PIXEL_FORMAT_YVYU:
+    case COGL_PIXEL_FORMAT_UYVY:
+    case COGL_PIXEL_FORMAT_VYUY:
+    case COGL_PIXEL_FORMAT_AYUV:
+    case COGL_PIXEL_FORMAT_XRGB8888_A8:
+    case COGL_PIXEL_FORMAT_XBGR8888_A8:
+    case COGL_PIXEL_FORMAT_RGBX8888_A8:
+    case COGL_PIXEL_FORMAT_BGRX8888_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:
+    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:
       g_assert_not_reached ();
 
     case COGL_PIXEL_FORMAT_A_8:
diff --git a/cogl/cogl/cogl-bitmap-packing.h b/cogl/cogl/cogl-bitmap-packing.h
index 3a1646fbf..1c8bbb5fc 100644
--- a/cogl/cogl/cogl-bitmap-packing.h
+++ b/cogl/cogl/cogl-bitmap-packing.h
@@ -395,7 +395,37 @@ G_PASTE (_cogl_unpack_, component_size) (CoglPixelFormat format,
     case COGL_PIXEL_FORMAT_DEPTH_32:
     case COGL_PIXEL_FORMAT_DEPTH_24_STENCIL_8:
     case COGL_PIXEL_FORMAT_ANY:
+    /* No support for YUV or multi-plane formats */
     case COGL_PIXEL_FORMAT_YUV:
+    case COGL_PIXEL_FORMAT_YUYV:
+    case COGL_PIXEL_FORMAT_YVYU:
+    case COGL_PIXEL_FORMAT_UYVY:
+    case COGL_PIXEL_FORMAT_VYUY:
+    case COGL_PIXEL_FORMAT_AYUV:
+    case COGL_PIXEL_FORMAT_XRGB8888_A8:
+    case COGL_PIXEL_FORMAT_XBGR8888_A8:
+    case COGL_PIXEL_FORMAT_RGBX8888_A8:
+    case COGL_PIXEL_FORMAT_BGRX8888_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:
+    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:
       g_assert_not_reached ();
     }
 }
@@ -751,7 +781,37 @@ G_PASTE (_cogl_pack_, component_size) (CoglPixelFormat format,
     case COGL_PIXEL_FORMAT_DEPTH_32:
     case COGL_PIXEL_FORMAT_DEPTH_24_STENCIL_8:
     case COGL_PIXEL_FORMAT_ANY:
+    /* No support for YUV or multi-plane formats */
     case COGL_PIXEL_FORMAT_YUV:
+    case COGL_PIXEL_FORMAT_YUYV:
+    case COGL_PIXEL_FORMAT_YVYU:
+    case COGL_PIXEL_FORMAT_UYVY:
+    case COGL_PIXEL_FORMAT_VYUY:
+    case COGL_PIXEL_FORMAT_AYUV:
+    case COGL_PIXEL_FORMAT_XRGB8888_A8:
+    case COGL_PIXEL_FORMAT_XBGR8888_A8:
+    case COGL_PIXEL_FORMAT_RGBX8888_A8:
+    case COGL_PIXEL_FORMAT_BGRX8888_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:
+    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:
       g_assert_not_reached ();
     }
 }
diff --git a/cogl/cogl/cogl-bitmap.c b/cogl/cogl/cogl-bitmap.c
index 5d5dbc30a..a20d268b7 100644
--- a/cogl/cogl/cogl-bitmap.c
+++ b/cogl/cogl/cogl-bitmap.c
@@ -136,7 +136,7 @@ _cogl_bitmap_copy_subregion (CoglBitmap *src,
                         (dst->format & ~COGL_PREMULT_BIT),
                         FALSE);
 
-  bpp = _cogl_pixel_format_get_bytes_per_pixel (src->format);
+  bpp = cogl_pixel_format_get_bytes_per_pixel_simple (src->format);
 
   if ((srcdata = _cogl_bitmap_map (src, COGL_BUFFER_ACCESS_READ, 0, error)))
     {
@@ -186,7 +186,7 @@ cogl_bitmap_new_for_data (CoglContext *context,
 
   /* Rowstride from width if not given */
   if (rowstride == 0)
-    rowstride = width * _cogl_pixel_format_get_bytes_per_pixel (format);
+    rowstride = width * cogl_pixel_format_get_bytes_per_pixel_simple (format);
 
   bmp = g_slice_new (CoglBitmap);
   bmp->context = context;
@@ -211,7 +211,7 @@ _cogl_bitmap_new_with_malloc_buffer (CoglContext *context,
                                      GError **error)
 {
   static CoglUserDataKey bitmap_free_key;
-  int bpp = _cogl_pixel_format_get_bytes_per_pixel (format);
+  int bpp = cogl_pixel_format_get_bytes_per_pixel_simple (format);
   int rowstride = ((width * bpp) + 3) & ~3;
   uint8_t *data = g_try_malloc (rowstride * height);
   CoglBitmap *bitmap;
@@ -308,7 +308,7 @@ cogl_bitmap_new_with_size (CoglContext *context,
 
   /* for now we fallback to cogl_pixel_buffer_new, later, we could ask
    * libdrm a tiled buffer for instance */
-  rowstride = width * _cogl_pixel_format_get_bytes_per_pixel (format);
+  rowstride = width * cogl_pixel_format_get_bytes_per_pixel_simple (format);
 
   pixel_buffer =
     cogl_pixel_buffer_new (context,
diff --git a/cogl/cogl/cogl-blit.c b/cogl/cogl/cogl-blit.c
index 26a9b2993..638572dc6 100644
--- a/cogl/cogl/cogl-blit.c
+++ b/cogl/cogl/cogl-blit.c
@@ -273,7 +273,7 @@ static gboolean
 _cogl_blit_get_tex_data_begin (CoglBlitData *data)
 {
   data->format = _cogl_texture_get_format (data->src_tex);
-  data->bpp = _cogl_pixel_format_get_bytes_per_pixel (data->format);
+  data->bpp = cogl_pixel_format_get_bytes_per_pixel_simple (data->format);
 
   data->image_data = g_malloc (data->bpp * data->src_width *
                                data->src_height);
diff --git a/cogl/cogl/cogl-framebuffer.c b/cogl/cogl/cogl-framebuffer.c
index de9bfb451..b2bfe6636 100644
--- a/cogl/cogl/cogl-framebuffer.c
+++ b/cogl/cogl/cogl-framebuffer.c
@@ -1315,7 +1315,7 @@ cogl_framebuffer_read_pixels (CoglFramebuffer *framebuffer,
                               CoglPixelFormat format,
                               uint8_t *pixels)
 {
-  int bpp = _cogl_pixel_format_get_bytes_per_pixel (format);
+  int bpp = cogl_pixel_format_get_bytes_per_pixel_simple (format);
   CoglBitmap *bitmap;
   gboolean ret;
 
diff --git a/cogl/cogl/cogl-pixel-format-conversion.c b/cogl/cogl/cogl-pixel-format-conversion.c
new file mode 100644
index 000000000..107595445
--- /dev/null
+++ b/cogl/cogl/cogl-pixel-format-conversion.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-gtype-private.h"
+#include "cogl-pixel-format-conversion.h"
+#include "cogl-snippet.h"
+#include "cogl-pipeline-layer-state.h"
+#include "cogl-pipeline-state.h"
+
+#define _COGL_YUV_TO_RGBA(res, y, u, v)                           \
+    "vec4 " res ";\n"                                             \
+    res ".r = (" y ") + 1.59765625 * (" v ");\n"                  \
+    res ".g = (" y ") - 0.390625 * (" u ") - 0.8125 * (" v ");\n" \
+    res ".b = (" y ") + 2.015625 * (" u ");\n"                    \
+    res ".a = 1.0;\n"
+
+/* Shader for a single YUV plane */
+static const char yuv_to_rgba_shader[] =
+    "vec4\n"
+    "cogl_yuv_to_rgba (vec2 UV)\n"
+    "{\n"
+    "  vec4 orig_color = texture2D(cogl_sampler0, UV);\n"
+    "  float y = 1.16438356 * (orig_color.r - 0.0625);\n"
+    "  float u = orig_color.g - 0.5;\n"
+    "  float v = orig_color.b - 0.5;\n"
+       _COGL_YUV_TO_RGBA ("color", "y", "u", "v")
+    "  return color;\n"
+    "}\n";
+
+/* Shader for 1 Y-plane and 1 UV-plane */
+static const char y_uv_to_rgba_shader[] =
+    "vec4\n"
+    "cogl_y_uv_to_rgba (vec2 UV)\n"
+    "{\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"
+       _COGL_YUV_TO_RGBA ("color", "y", "u", "v")
+    "  return color;\n"
+    "}\n";
+
+/* Shader for 1 Y-plane, 1 U-plane and 1 V-plane */
+static const char y_u_v_to_rgba_shader[] =
+    "vec4\n"
+    "cogl_y_u_v_to_rgba (vec2 UV)\n"
+    "{\n"
+    "  float y = 1.16438356 * (texture2D(cogl_sampler0, UV).x - 0.0625);\n"
+    "  float u = texture2D(cogl_sampler1, UV).x - 0.5;\n"
+    "  float v = texture2D(cogl_sampler2, UV).x - 0.5;\n"
+       _COGL_YUV_TO_RGBA ("color", "y", "u", "v")
+    "  return color;\n"
+    "}\n";
+
+struct _CoglPixelFormatConversion
+{
+  CoglObject _parent;
+
+  CoglSnippet *vertex_declaration_snippet;
+  CoglSnippet *fragment_declaration_snippet;
+
+  CoglSnippet *fragment_execution_snippet;
+};
+
+static void
+_cogl_pixel_format_conversion_free (CoglPixelFormatConversion *self);
+
+COGL_OBJECT_DEFINE (PixelFormatConversion, pixel_format_conversion);
+COGL_GTYPE_DEFINE_CLASS (PixelFormatConversion, pixel_format_conversion);
+
+
+void
+cogl_pixel_format_conversion_attach_to_pipeline (CoglPixelFormatConversion *self,
+                                                 CoglPipeline *pipeline,
+                                                 gint layer)
+{
+  cogl_pipeline_add_snippet (pipeline, self->fragment_declaration_snippet);
+  cogl_pipeline_add_snippet (pipeline, self->vertex_declaration_snippet);
+
+  cogl_pipeline_add_layer_snippet (pipeline,
+                                   layer,
+                                   self->fragment_execution_snippet);
+}
+
+static gboolean
+get_cogl_snippets (CoglPixelFormat format,
+                   CoglSnippet **vertex_snippet_out,
+                   CoglSnippet **fragment_snippet_out,
+                   CoglSnippet **layer_snippet_out)
+{
+  const char *global_hook;
+  const char *layer_hook;
+
+  switch (format)
+    {
+    case COGL_PIXEL_FORMAT_AYUV:
+      global_hook = yuv_to_rgba_shader;
+      layer_hook = "cogl_layer = cogl_yuv_to_rgba(cogl_tex_coord0_in.st);\n";
+      break;
+    case COGL_PIXEL_FORMAT_NV12:
+      /* XXX are we using Y_UV or Y_xUxV? Maybe check for RG support? */
+      global_hook = y_uv_to_rgba_shader;
+      layer_hook = "cogl_layer = cogl_y_uv_to_rgba(cogl_tex_coord0_in.st);\n";
+      break;
+    case COGL_PIXEL_FORMAT_YUV444:
+    case COGL_PIXEL_FORMAT_YUV422:
+      global_hook = y_u_v_to_rgba_shader;
+      layer_hook = "cogl_layer = cogl_y_u_v_to_rgba(cogl_tex_coord0_in.st);\n";
+      break;
+    default:
+      *vertex_snippet_out = NULL;
+      *fragment_snippet_out = NULL;
+      *layer_snippet_out = NULL;
+      return FALSE;
+    }
+
+  *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);
+
+  return TRUE;
+}
+
+static void
+_cogl_pixel_format_conversion_free (CoglPixelFormatConversion *self)
+{
+  cogl_clear_object (&self->vertex_declaration_snippet);
+  cogl_clear_object (&self->fragment_declaration_snippet);
+  cogl_clear_object (&self->fragment_execution_snippet);
+}
+
+CoglPixelFormatConversion *
+cogl_pixel_format_conversion_new (CoglPixelFormat format)
+{
+  CoglPixelFormatConversion *self;
+  CoglSnippet *vertex_declaration_snippet;
+  CoglSnippet *fragment_declaration_snippet;
+  CoglSnippet *fragment_execution_snippet;
+
+  if (!get_cogl_snippets (format,
+                          &vertex_declaration_snippet,
+                          &fragment_declaration_snippet,
+                          &fragment_execution_snippet))
+    return NULL;
+
+  self = g_slice_new0 (CoglPixelFormatConversion);
+  _cogl_pixel_format_conversion_object_new (self);
+
+  self->vertex_declaration_snippet = vertex_declaration_snippet;
+  self->fragment_declaration_snippet = fragment_declaration_snippet;
+  self->fragment_execution_snippet = fragment_execution_snippet;
+
+  return self;
+}
diff --git a/cogl/cogl/cogl-pixel-format-conversion.h b/cogl/cogl/cogl-pixel-format-conversion.h
new file mode 100644
index 000000000..f93107a33
--- /dev/null
+++ b/cogl/cogl/cogl-pixel-format-conversion.h
@@ -0,0 +1,92 @@
+/*
+ * 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_PIXEL_FORMAT_CONVERSION_H__
+#define __COGL_PIXEL_FORMAT_CONVERSION_H__
+
+#include "cogl/cogl-types.h"
+#include "cogl/cogl-pipeline.h"
+
+G_BEGIN_DECLS
+
+/**
+ * SECTION:cogl-color-space-conversion
+ * @title: CoglPixelFormatConversion
+ * @short_description: A collection of snippets to handle pixel_format conversion
+ *
+ * In some use cases, one might generate non-RGBA textures (e.g. YUV), which is
+ * problematic if you then have to composite them in to an RGBA framebuffer. In
+ * comes #CoglPixelFormatConversion, which you can attach to a #CoglPipeline to
+ * do this all for you. Internally, it consists of nothing more than a
+ * collection of #CoglSnippets which do the right thing for you.
+ */
+
+typedef struct _CoglPixelFormatConversion CoglPixelFormatConversion;
+#define COGL_PIXEL_FORMAT_CONVERSION(ptr) ((CoglPixelFormatConversion *) ptr)
+
+
+/**
+ * cogl_multiplane_texture_get_gtype:
+ *
+ * Returns: a #GType that can be used with the GLib type system.
+ */
+GType cogl_pixel_format_conversion_get_gtype (void);
+
+/*
+ * cogl_is_pixel_format_conversion:
+ * @object: A #CoglObject pointer
+ *
+ * Gets whether the given @object references an existing
+ * CoglPixelFormatConversion.
+ *
+ * Return value: %TRUE if the @object references a #CoglPixelFormatConversion,
+ *   %FALSE otherwise
+ */
+gboolean
+cogl_is_pixel_format_conversion (void *object);
+
+/**
+ * cogl_pixel_format_conversion_new:
+ * @format: The input format
+ *
+ * Creates a #CoglPixelFormatConversion to convert the given @formatro RGBA. If
+ * no such conversion is needed, it will return %NULL.
+ *
+ * Returns: (transfer full) (nullable): A new #CoglPixelFormatConversion, or
+ * %NULL if none is needed.
+ */
+CoglPixelFormatConversion * cogl_pixel_format_conversion_new  (CoglPixelFormat format);
+
+/**
+ * cogl_pixel_format_conversion_attach_to_pipeline:
+ * @self: The #CoglPixelFormatConversion you want to add
+ * @pipeline: The #CoglPipeline which needs the color conversion
+ * @layer: The layer you want to perform the color space conversion at
+ *
+ * Adds color conversion to the given @pipeline at the given @layer.
+ */
+void cogl_pixel_format_conversion_attach_to_pipeline (CoglPixelFormatConversion *self,
+                                                      CoglPipeline *pipeline,
+                                                      int layer);
+
+G_END_DECLS
+
+#endif
diff --git a/cogl/cogl/cogl-pixel-format.c b/cogl/cogl/cogl-pixel-format.c
index a62388469..0a28f0993 100644
--- a/cogl/cogl/cogl-pixel-format.c
+++ b/cogl/cogl/cogl-pixel-format.c
@@ -35,241 +35,667 @@
 #include <stdlib.h>
 
 #include "cogl-pixel-format.h"
+#include "cogl-texture.h"
 
 /* An entry to map CoglPixelFormats to their respective properties */
 typedef struct _CoglPixelFormatInfo
 {
   CoglPixelFormat cogl_format;
   const char *format_str;
-  int bpp;                         /* Bytes per pixel                 */
-  int aligned;                     /* Aligned components? (-1 if n/a) */
+  int aligned;                               /* Is aligned? (bool; -1 if n/a) */
+  uint8_t n_planes;
+
+  /* Per plane-information */
+  uint8_t bpp[COGL_PIXEL_FORMAT_MAX_PLANES];        /* Bytes per pixel        */
+  uint8_t hsub[COGL_PIXEL_FORMAT_MAX_PLANES];       /* horizontal subsampling */
+  uint8_t vsub[COGL_PIXEL_FORMAT_MAX_PLANES];       /* vertical subsampling   */
+  CoglPixelFormat subformats[COGL_PIXEL_FORMAT_MAX_PLANES]; /* how to upload to GL    */
 } CoglPixelFormatInfo;
 
 static const CoglPixelFormatInfo format_info_table[] = {
   {
     .cogl_format = COGL_PIXEL_FORMAT_ANY,
     .format_str = "ANY",
-    .bpp = 0,
-    .aligned = -1
+    .n_planes = 0,
+    .aligned = -1,
+    .bpp = { 0 },
+    .hsub = { 1, 0, 0, 0 },
+    .vsub = { 1, 0, 0, 0 },
+    .subformats = { COGL_PIXEL_FORMAT_ANY }
   },
   {
     .cogl_format = COGL_PIXEL_FORMAT_A_8,
     .format_str = "A_8",
-    .bpp = 1,
-    .aligned = 1
+    .n_planes = 1,
+    .aligned = 1,
+    .bpp = { 1 },
+    .hsub = { 1, 0, 0, 0 },
+    .vsub = { 1, 0, 0, 0 },
+    .subformats = { COGL_PIXEL_FORMAT_A_8 }
   },
   {
     .cogl_format = COGL_PIXEL_FORMAT_RGB_565,
     .format_str = "RGB_565",
-    .bpp = 2,
-    .aligned = 0
+    .n_planes = 1,
+    .aligned = 0,
+    .bpp = { 2 },
+    .hsub = { 1, 0, 0, 0 },
+    .vsub = { 1, 0, 0, 0 },
+    .subformats = { COGL_PIXEL_FORMAT_RGB_565 }
   },
   {
     .cogl_format = COGL_PIXEL_FORMAT_RGBA_4444,
     .format_str = "RGBA_4444",
-    .bpp = 2,
-    .aligned = 0
+    .n_planes = 1,
+    .aligned = 0,
+    .bpp = { 2 },
+    .hsub = { 1, 0, 0, 0 },
+    .vsub = { 1, 0, 0, 0 },
+    .subformats = { COGL_PIXEL_FORMAT_RGBA_4444 }
   },
   {
     .cogl_format = COGL_PIXEL_FORMAT_RGBA_5551,
     .format_str = "RGBA_5551",
-    .bpp = 2,
-    .aligned = 0
+    .n_planes = 1,
+    .aligned = 0,
+    .bpp = { 2 },
+    .hsub = { 1, 0, 0, 0 },
+    .vsub = { 1, 0, 0, 0 },
+    .subformats = { COGL_PIXEL_FORMAT_RGBA_5551 }
   },
   {
     .cogl_format = COGL_PIXEL_FORMAT_YUV,
     .format_str = "YUV",
-    .bpp = 0,
-    .aligned = -1
+    .n_planes = 1,
+    .aligned = -1,
+    .bpp = { 0 },
+    .hsub = { 1, 0, 0, 0 },
+    .vsub = { 1, 0, 0, 0 },
+    .subformats = { COGL_PIXEL_FORMAT_YUV }
   },
   {
     .cogl_format = COGL_PIXEL_FORMAT_R_8,
     .format_str = "R_8",
-    .bpp = 1,
-    .aligned = 1
+    .n_planes = 1,
+    .aligned = 1,
+    .bpp = { 1 },
+    .hsub = { 1, 0, 0, 0 },
+    .vsub = { 1, 0, 0, 0 },
+    .subformats = { COGL_PIXEL_FORMAT_R_8 }
   },
   {
     .cogl_format = COGL_PIXEL_FORMAT_RG_88,
     .format_str = "RG_88",
-    .bpp = 2,
-    .aligned = 1
+    .n_planes = 1,
+    .aligned = 1,
+    .bpp = { 2 },
+    .hsub = { 1, 0, 0, 0 },
+    .vsub = { 1, 0, 0, 0 },
+    .subformats = { COGL_PIXEL_FORMAT_RG_88 }
   },
   {
     .cogl_format = COGL_PIXEL_FORMAT_RGB_888,
     .format_str = "RGB_888",
-    .bpp = 3,
-    .aligned = 1
+    .n_planes = 1,
+    .aligned = 1,
+    .bpp = { 3 },
+    .hsub = { 1, 0, 0, 0 },
+    .vsub = { 1, 0, 0, 0 },
+    .subformats = { COGL_PIXEL_FORMAT_RGB_888 }
   },
   {
     .cogl_format = COGL_PIXEL_FORMAT_BGR_888,
     .format_str = "BGR_888",
-    .bpp = 3,
-    .aligned = 1
+    .n_planes = 1,
+    .aligned = 1,
+    .bpp = { 3 },
+    .hsub = { 1, 0, 0, 0 },
+    .vsub = { 1, 0, 0, 0 },
+    .subformats = { COGL_PIXEL_FORMAT_BGR_888 }
   },
   {
     .cogl_format = COGL_PIXEL_FORMAT_RGBA_8888,
     .format_str = "RGBA_8888",
-    .bpp = 4,
-    .aligned = 1
+    .n_planes = 1,
+    .aligned = 1,
+    .bpp = { 4 },
+    .hsub = { 1, 0, 0, 0 },
+    .vsub = { 1, 0, 0, 0 },
+    .subformats = { COGL_PIXEL_FORMAT_RGBA_8888 }
   },
   {
     .cogl_format = COGL_PIXEL_FORMAT_BGRA_8888,
     .format_str = "BGRA_8888",
-    .bpp = 4,
-    .aligned = 1
+    .n_planes = 1,
+    .aligned = 1,
+    .bpp = { 4 },
+    .hsub = { 1, 0, 0, 0 },
+    .vsub = { 1, 0, 0, 0 },
+    .subformats = { COGL_PIXEL_FORMAT_BGRA_8888 }
   },
   {
     .cogl_format = COGL_PIXEL_FORMAT_ARGB_8888,
     .format_str = "ARGB_8888",
-    .bpp = 4,
-    .aligned = 1
+    .n_planes = 1,
+    .aligned = 1,
+    .bpp = { 4 },
+    .hsub = { 1, 0, 0, 0 },
+    .vsub = { 1, 0, 0, 0 },
+    .subformats = { COGL_PIXEL_FORMAT_ARGB_8888 }
   },
   {
     .cogl_format = COGL_PIXEL_FORMAT_ABGR_8888,
     .format_str = "ABGR_8888",
-    .bpp = 4,
-    .aligned = 1
+    .n_planes = 1,
+    .aligned = 1,
+    .bpp = { 4 },
+    .hsub = { 1, 0, 0, 0 },
+    .vsub = { 1, 0, 0, 0 },
+    .subformats = { COGL_PIXEL_FORMAT_ABGR_8888 }
   },
   {
     .cogl_format = COGL_PIXEL_FORMAT_RGBA_1010102,
     .format_str = "RGBA_1010102",
-    .bpp = 4,
-    .aligned = 0
+    .n_planes = 1,
+    .aligned = 0,
+    .bpp = { 4 },
+    .hsub = { 1, 0, 0, 0 },
+    .vsub = { 1, 0, 0, 0 },
+    .subformats = { COGL_PIXEL_FORMAT_RGBA_1010102 }
   },
   {
     .cogl_format = COGL_PIXEL_FORMAT_BGRA_1010102,
     .format_str = "BGRA_1010102",
-    .bpp = 4,
-    .aligned = 0
+    .n_planes = 1,
+    .aligned = 0,
+    .bpp = { 4 },
+    .hsub = { 1, 0, 0, 0 },
+    .vsub = { 1, 0, 0, 0 },
+    .subformats = { COGL_PIXEL_FORMAT_BGRA_1010102 }
   },
   {
     .cogl_format = COGL_PIXEL_FORMAT_ARGB_2101010,
     .format_str = "ARGB_2101010",
-    .bpp = 4,
-    .aligned = 0
+    .n_planes = 1,
+    .aligned = 0,
+    .bpp = { 4 },
+    .hsub = { 1, 0, 0, 0 },
+    .vsub = { 1, 0, 0, 0 },
+    .subformats = { COGL_PIXEL_FORMAT_ARGB_2101010 }
   },
   {
     .cogl_format = COGL_PIXEL_FORMAT_ABGR_2101010,
     .format_str = "ABGR_2101010",
-    .bpp = 4,
-    .aligned = 0
+    .n_planes = 1,
+    .aligned = 0,
+    .bpp = { 4 },
+    .hsub = { 1, 0, 0, 0 },
+    .vsub = { 1, 0, 0, 0 },
+    .subformats = { COGL_PIXEL_FORMAT_ABGR_2101010 }
   },
   {
     .cogl_format = COGL_PIXEL_FORMAT_RGBA_8888_PRE,
     .format_str = "RGBA_8888_PRE",
-    .bpp = 4,
-    .aligned = 1
+    .n_planes = 1,
+    .aligned = 1,
+    .bpp = { 4 },
+    .hsub = { 1, 0, 0, 0 },
+    .vsub = { 1, 0, 0, 0 },
+    .subformats = { COGL_PIXEL_FORMAT_RGBA_8888_PRE }
   },
   {
     .cogl_format = COGL_PIXEL_FORMAT_BGRA_8888_PRE,
     .format_str = "BGRA_8888_PRE",
-    .bpp = 4,
-    .aligned = 1
+    .n_planes = 1,
+    .aligned = 1,
+    .bpp = { 4 },
+    .hsub = { 1, 0, 0, 0 },
+    .vsub = { 1, 0, 0, 0 },
+    .subformats = { COGL_PIXEL_FORMAT_BGRA_8888_PRE }
   },
   {
     .cogl_format = COGL_PIXEL_FORMAT_ARGB_8888_PRE,
     .format_str = "ARGB_8888_PRE",
-    .bpp = 4,
-    .aligned = 1
+    .n_planes = 1,
+    .aligned = 1,
+    .bpp = { 4 },
+    .hsub = { 1, 0, 0, 0 },
+    .vsub = { 1, 0, 0, 0 },
+    .subformats = { COGL_PIXEL_FORMAT_ARGB_8888_PRE }
   },
   {
     .cogl_format = COGL_PIXEL_FORMAT_ABGR_8888_PRE,
     .format_str = "ABGR_8888_PRE",
-    .bpp = 4,
-    .aligned = 1
+    .n_planes = 1,
+    .aligned = 1,
+    .bpp = { 4 },
+    .hsub = { 1, 0, 0, 0 },
+    .vsub = { 1, 0, 0, 0 },
+    .subformats = { COGL_PIXEL_FORMAT_ABGR_8888_PRE }
   },
   {
     .cogl_format = COGL_PIXEL_FORMAT_RGBA_4444_PRE,
     .format_str = "RGBA_4444_PRE",
-    .bpp = 2,
-    .aligned = 0
+    .n_planes = 1,
+    .aligned = 0,
+    .bpp = { 2 },
+    .hsub = { 1, 0, 0, 0 },
+    .vsub = { 1, 0, 0, 0 },
+    .subformats = { COGL_PIXEL_FORMAT_RGBA_4444_PRE }
   },
   {
     .cogl_format = COGL_PIXEL_FORMAT_RGBA_5551_PRE,
     .format_str = "RGBA_5551_PRE",
-    .bpp = 2,
-    .aligned = 0
+    .n_planes = 1,
+    .aligned = 0,
+    .bpp = { 2 },
+    .hsub = { 1, 0, 0, 0 },
+    .vsub = { 1, 0, 0, 0 },
+    .subformats = { COGL_PIXEL_FORMAT_RGBA_5551_PRE }
   },
   {
     .cogl_format = COGL_PIXEL_FORMAT_RGBA_1010102_PRE,
     .format_str = "RGBA_1010102_PRE",
-    .bpp = 4,
-    .aligned = 0
+    .n_planes = 1,
+    .aligned = 0,
+    .bpp = { 4 },
+    .hsub = { 1, 0, 0, 0 },
+    .vsub = { 1, 0, 0, 0 },
+    .subformats = { COGL_PIXEL_FORMAT_RGBA_1010102_PRE }
   },
   {
     .cogl_format = COGL_PIXEL_FORMAT_BGRA_1010102_PRE,
     .format_str = "BGRA_1010102_PRE",
-    .bpp = 4,
-    .aligned = 0
+    .n_planes = 1,
+    .aligned = 0,
+    .bpp = { 4 },
+    .hsub = { 1, 0, 0, 0 },
+    .vsub = { 1, 0, 0, 0 },
+    .subformats = { COGL_PIXEL_FORMAT_BGRA_1010102_PRE }
   },
   {
     .cogl_format = COGL_PIXEL_FORMAT_ARGB_2101010_PRE,
     .format_str = "ARGB_2101010_PRE",
-    .bpp = 4,
-    .aligned = 0
+    .n_planes = 1,
+    .aligned = 0,
+    .bpp = { 4 },
+    .hsub = { 1, 0, 0, 0 },
+    .vsub = { 1, 0, 0, 0 },
+    .subformats = { COGL_PIXEL_FORMAT_ARGB_2101010_PRE }
   },
   {
     .cogl_format = COGL_PIXEL_FORMAT_ABGR_2101010_PRE,
     .format_str = "ABGR_2101010_PRE",
-    .bpp = 4,
-    .aligned = 0
+    .n_planes = 1,
+    .aligned = 0,
+    .bpp = { 4 },
+    .hsub = { 1, 0, 0, 0 },
+    .vsub = { 1, 0, 0, 0 },
+    .subformats = { COGL_PIXEL_FORMAT_ABGR_2101010_PRE }
   },
   {
     .cogl_format = COGL_PIXEL_FORMAT_DEPTH_16,
     .format_str = "DEPTH_16",
-    .bpp = 2,
-    .aligned = 1
+    .n_planes = 1,
+    .aligned = 1,
+    .bpp = { 2 },
+    .hsub = { 1, 0, 0, 0 },
+    .vsub = { 1, 0, 0, 0 },
+    .subformats = { COGL_PIXEL_FORMAT_DEPTH_16 }
   },
   {
     .cogl_format = COGL_PIXEL_FORMAT_DEPTH_32,
     .format_str = "DEPTH_32",
-    .bpp = 4,
-    .aligned = 1
+    .n_planes = 1,
+    .aligned = 1,
+    .bpp = { 4 },
+    .hsub = { 1, 0, 0, 0 },
+    .vsub = { 1, 0, 0, 0 },
+    .subformats = { COGL_PIXEL_FORMAT_DEPTH_32 }
   },
   {
     .cogl_format = COGL_PIXEL_FORMAT_DEPTH_24_STENCIL_8,
     .format_str = "DEPTH_24_STENCIL_8",
-    .bpp = 4,
-    .aligned = 1
+    .n_planes = 1,
+    .aligned = 1,
+    .bpp = { 4 },
+    .hsub = { 1, 0, 0, 0 },
+    .vsub = { 1, 0, 0, 0 },
+    .subformats = { COGL_PIXEL_FORMAT_DEPTH_24_STENCIL_8 }
+  },
+  /* Packed YUV */
+  {
+    .cogl_format = COGL_PIXEL_FORMAT_YUYV,
+    .format_str = "YUYV",
+    .n_planes = 2,
+    .aligned = 0,
+    .bpp = { 4 },
+    .hsub = { 1, 0, 0, 0 },
+    .vsub = { 1, 0, 0, 0 },
+    .subformats = { COGL_PIXEL_FORMAT_YUYV, COGL_PIXEL_FORMAT_YUYV }
+  },
+  {
+    .cogl_format = COGL_PIXEL_FORMAT_YVYU,
+    .format_str = "YVYU",
+    .n_planes = 2,
+    .aligned = 0,
+    .bpp = { 4 },
+    .hsub = { 1, 0, 0, 0 },
+    .vsub = { 1, 0, 0, 0 },
+    .subformats = { COGL_PIXEL_FORMAT_YVYU, COGL_PIXEL_FORMAT_YVYU }
+  },
+  {
+    .cogl_format = COGL_PIXEL_FORMAT_UYVY,
+    .format_str = "UYVY",
+    .n_planes = 2,
+    .aligned = 0,
+    .bpp = { 4 },
+    .hsub = { 1, 0, 0, 0 },
+    .vsub = { 1, 0, 0, 0 },
+    .subformats = { COGL_PIXEL_FORMAT_UYVY, COGL_PIXEL_FORMAT_UYVY }
+  },
+  {
+    .cogl_format = COGL_PIXEL_FORMAT_VYUY,
+    .format_str = "VYUY",
+    .n_planes = 2,
+    .aligned = 0,
+    .bpp = { 4 },
+    .hsub = { 1, 0, 0, 0 },
+    .vsub = { 1, 0, 0, 0 },
+    .subformats = { COGL_PIXEL_FORMAT_VYUY, COGL_PIXEL_FORMAT_VYUY }
+  },
+  {
+    .cogl_format = COGL_PIXEL_FORMAT_AYUV,
+    .format_str = "AYUV",
+    .n_planes = 2,
+    .aligned = 0,
+    .bpp = { 4 },
+    .hsub = { 1, 0, 0, 0 },
+    .vsub = { 1, 0, 0, 0 },
+    .subformats = { COGL_PIXEL_FORMAT_AYUV, COGL_PIXEL_FORMAT_AYUV }
+  },
+  /* 2 plane RGB + A */
+  {
+    .cogl_format = COGL_PIXEL_FORMAT_XRGB8888_A8,
+    .format_str = "XRGB8888_A8",
+    .n_planes = 2,
+    .aligned = 0,
+    .bpp = { 4, 1 },
+    .hsub = { 1, 1, 0, 0 },
+    .vsub = { 1, 1, 0, 0 },
+    .subformats = { COGL_PIXEL_FORMAT_ARGB_8888, COGL_PIXEL_FORMAT_A_8 }
+  },
+  {
+    .cogl_format = COGL_PIXEL_FORMAT_XBGR8888_A8,
+    .format_str = "XBGR8888_A8",
+    .n_planes = 2,
+    .aligned = 0,
+    .bpp = { 4, 1 },
+    .hsub = { 1, 1, 0, 0 },
+    .vsub = { 1, 1, 0, 0 },
+    .subformats = { COGL_PIXEL_FORMAT_ABGR_8888, COGL_PIXEL_FORMAT_A_8 }
+  },
+  {
+    .cogl_format = COGL_PIXEL_FORMAT_RGBX8888_A8,
+    .format_str = "RGBX8888_A8",
+    .n_planes = 2,
+    .aligned = 0,
+    .bpp = { 4, 1 },
+    .hsub = { 1, 1, 0, 0 },
+    .vsub = { 1, 1, 0, 0 },
+    .subformats = { COGL_PIXEL_FORMAT_RGBA_8888, COGL_PIXEL_FORMAT_A_8 }
+  },
+  {
+    .cogl_format = COGL_PIXEL_FORMAT_BGRX8888_A8,
+    .format_str = "BGRX8888_A8",
+    .n_planes = 2,
+    .aligned = 0,
+    .bpp = { 4, 1 },
+    .hsub = { 1, 1, 0, 0 },
+    .vsub = { 1, 1, 0, 0 },
+    .subformats = { COGL_PIXEL_FORMAT_BGRA_8888, COGL_PIXEL_FORMAT_A_8 }
+  },
+  {
+    .cogl_format = COGL_PIXEL_FORMAT_RGB888_A8,
+    .format_str = "RGB888_A8",
+    .n_planes = 2,
+    .aligned = 0,
+    .bpp = { 3, 1 },
+    .hsub = { 1, 1, 0, 0 },
+    .vsub = { 1, 1, 0, 0 },
+    .subformats = { COGL_PIXEL_FORMAT_RGB_888, COGL_PIXEL_FORMAT_A_8 }
+  },
+  {
+    .cogl_format = COGL_PIXEL_FORMAT_BGR888_A8,
+    .format_str = "BGR888_A8",
+    .n_planes = 2,
+    .aligned = 0,
+    .bpp = { 3, 1 },
+    .hsub = { 1, 1, 0, 0 },
+    .vsub = { 1, 1, 0, 0 },
+    .subformats = { COGL_PIXEL_FORMAT_BGR_888, COGL_PIXEL_FORMAT_A_8 }
+  },
+  {
+    .cogl_format = COGL_PIXEL_FORMAT_RGB565_A8,
+    .format_str = "RGB565_A8",
+    .n_planes = 2,
+    .aligned = 0,
+    .bpp = { 2, 1 },
+    .hsub = { 1, 1, 0, 0 },
+    .vsub = { 1, 1, 0, 0 },
+    .subformats = { COGL_PIXEL_FORMAT_RGB_565, COGL_PIXEL_FORMAT_A_8 }
+  },
+  {
+    .cogl_format = COGL_PIXEL_FORMAT_BGR565_A8,
+    .format_str = "BGR565_A8",
+    .n_planes = 2,
+    .aligned = 0,
+    .bpp = { 2, 1 },
+    .hsub = { 1, 1, 0, 0 },
+    .vsub = { 1, 1, 0, 0 },
+    .subformats = { COGL_PIXEL_FORMAT_RGB_565, COGL_PIXEL_FORMAT_A_8 }
+  },
+  /* 2 plane YUV */
+  {
+    .cogl_format = COGL_PIXEL_FORMAT_NV12,
+    .format_str = "NV12",
+    .n_planes = 2,
+    .aligned = 0,
+    .bpp = { 1, 2 },
+    .hsub = { 1, 2, 0, 0 },
+    .vsub = { 1, 2, 0, 0 },
+    .subformats = { COGL_PIXEL_FORMAT_R_8, COGL_PIXEL_FORMAT_RG_88 }
+  },
+  {
+    .cogl_format = COGL_PIXEL_FORMAT_NV21,
+    .format_str = "NV21",
+    .n_planes = 2,
+    .aligned = 0,
+    .bpp = { 1, 2 },
+    .hsub = { 1, 2, 0, 0 },
+    .vsub = { 1, 2, 0, 0 },
+    .subformats = { COGL_PIXEL_FORMAT_R_8, COGL_PIXEL_FORMAT_RG_88 }
+  },
+  {
+    .cogl_format = COGL_PIXEL_FORMAT_NV16,
+    .format_str = "NV16",
+    .n_planes = 2,
+    .aligned = 0,
+    .bpp = { 1, 2 },
+    .hsub = { 1, 2, 0, 0 },
+    .vsub = { 1, 1, 0, 0 },
+    .subformats = { COGL_PIXEL_FORMAT_R_8, COGL_PIXEL_FORMAT_RG_88 }
+  },
+  {
+    .cogl_format = COGL_PIXEL_FORMAT_NV61,
+    .format_str = "NV61",
+    .n_planes = 2,
+    .aligned = 0,
+    .bpp = { 1, 2 },
+    .hsub = { 1, 2, 0, 0 },
+    .vsub = { 1, 1, 0, 0 },
+    .subformats = { COGL_PIXEL_FORMAT_R_8, COGL_PIXEL_FORMAT_RG_88 }
+  },
+  {
+    .cogl_format = COGL_PIXEL_FORMAT_NV24,
+    .format_str = "NV24",
+    .n_planes = 2,
+    .aligned = 0,
+    .bpp = { 1, 2 },
+    .hsub = { 1, 1, 0, 0 },
+    .vsub = { 1, 1, 0, 0 },
+    .subformats = { COGL_PIXEL_FORMAT_R_8, COGL_PIXEL_FORMAT_RG_88 }
+  },
+  {
+    .cogl_format = COGL_PIXEL_FORMAT_NV42,
+    .format_str = "NV42",
+    .n_planes = 2,
+    .aligned = 0,
+    .bpp = { 1, 2 },
+    .hsub = { 1, 1, 0, 0 },
+    .vsub = { 1, 1, 0, 0 },
+    .subformats = { COGL_PIXEL_FORMAT_R_8, COGL_PIXEL_FORMAT_RG_88 }
+  },
+  /* 3 plane YUV */
+  {
+    .cogl_format = COGL_PIXEL_FORMAT_YUV410,
+    .format_str = "YUV410",
+    .n_planes = 3,
+    .aligned = 0,
+    .bpp = { 1, 1, 1 },
+    .hsub = { 1, 4, 4, 0 },
+    .vsub = { 1, 4, 4, 0 },
+    .subformats = { COGL_PIXEL_FORMAT_R_8, COGL_PIXEL_FORMAT_R_8, COGL_PIXEL_FORMAT_R_8 }
+  },
+  {
+    .cogl_format = COGL_PIXEL_FORMAT_YVU410,
+    .format_str = "YVU410",
+    .n_planes = 3,
+    .aligned = 0,
+    .bpp = { 1, 1, 1 },
+    .hsub = { 1, 4, 4, 0 },
+    .vsub = { 1, 4, 4, 0 },
+    .subformats = { COGL_PIXEL_FORMAT_R_8, COGL_PIXEL_FORMAT_R_8, COGL_PIXEL_FORMAT_R_8 }
+  },
+  {
+    .cogl_format = COGL_PIXEL_FORMAT_YUV411,
+    .format_str = "YUV411",
+    .n_planes = 3,
+    .aligned = 0,
+    .bpp = { 1, 1, 1 },
+    .hsub = { 1, 4, 4, 0 },
+    .vsub = { 1, 1, 1, 0 },
+    .subformats = { COGL_PIXEL_FORMAT_R_8, COGL_PIXEL_FORMAT_R_8, COGL_PIXEL_FORMAT_R_8 }
+  },
+  {
+    .cogl_format = COGL_PIXEL_FORMAT_YVU411,
+    .format_str = "YVU411",
+    .n_planes = 3,
+    .aligned = 0,
+    .bpp = { 1, 1, 1 },
+    .hsub = { 1, 4, 4, 0 },
+    .vsub = { 1, 1, 1, 0 },
+    .subformats = { COGL_PIXEL_FORMAT_R_8, COGL_PIXEL_FORMAT_R_8, COGL_PIXEL_FORMAT_R_8 }
+  },
+  {
+    .cogl_format = COGL_PIXEL_FORMAT_YUV420,
+    .format_str = "YUV420",
+    .n_planes = 3,
+    .aligned = 0,
+    .bpp = { 1, 1, 1 },
+    .hsub = { 1, 2, 2, 0 },
+    .vsub = { 1, 2, 2, 0 },
+    .subformats = { COGL_PIXEL_FORMAT_R_8, COGL_PIXEL_FORMAT_R_8, COGL_PIXEL_FORMAT_R_8 }
+  },
+  {
+    .cogl_format = COGL_PIXEL_FORMAT_YVU420,
+    .format_str = "YVU420",
+    .n_planes = 3,
+    .aligned = 0,
+    .bpp = { 1, 1, 1 },
+    .hsub = { 1, 2, 2, 0 },
+    .vsub = { 1, 2, 2, 0 },
+    .subformats = { COGL_PIXEL_FORMAT_R_8, COGL_PIXEL_FORMAT_R_8, COGL_PIXEL_FORMAT_R_8 }
+  },
+  {
+    .cogl_format = COGL_PIXEL_FORMAT_YUV422,
+    .format_str = "YUV422",
+    .n_planes = 3,
+    .aligned = 0,
+    .bpp = { 1, 1, 1 },
+    .hsub = { 1, 2, 2, 0 },
+    .vsub = { 1, 1, 1, 0 },
+    .subformats = { COGL_PIXEL_FORMAT_R_8, COGL_PIXEL_FORMAT_R_8, COGL_PIXEL_FORMAT_R_8 }
+  },
+  {
+    .cogl_format = COGL_PIXEL_FORMAT_YVU422,
+    .format_str = "YVU422",
+    .n_planes = 3,
+    .aligned = 0,
+    .bpp = { 1, 1, 1 },
+    .hsub = { 1, 2, 2, 0 },
+    .vsub = { 1, 1, 1, 0 },
+    .subformats = { COGL_PIXEL_FORMAT_R_8, COGL_PIXEL_FORMAT_R_8, COGL_PIXEL_FORMAT_R_8 }
+  },
+  {
+    .cogl_format = COGL_PIXEL_FORMAT_YUV444,
+    .format_str = "YUV444",
+    .n_planes = 3,
+    .aligned = 0,
+    .bpp = { 1, 1, 1 },
+    .hsub = { 1, 1, 1, 0 },
+    .vsub = { 1, 1, 1, 0 },
+    .subformats = { COGL_PIXEL_FORMAT_R_8, COGL_PIXEL_FORMAT_R_8, COGL_PIXEL_FORMAT_R_8 }
+  },
+  {
+    .cogl_format = COGL_PIXEL_FORMAT_YVU444,
+    .format_str = "YVU444",
+    .n_planes = 3,
+    .aligned = 0,
+    .bpp = { 1, 1, 1 },
+    .hsub = { 1, 1, 1, 0 },
+    .vsub = { 1, 1, 1, 0 },
+    .subformats = { COGL_PIXEL_FORMAT_R_8, COGL_PIXEL_FORMAT_R_8, COGL_PIXEL_FORMAT_R_8 }
   },
 };
 
-/*
- * Returns the number of bytes-per-pixel of a given format. The bpp
- * can be extracted from the least significant nibble of the pixel
- * format (see CoglPixelFormat).
- *
- * The mapping is the following (see discussion on bug #660188):
- *
- * 0     = undefined
- * 1, 8  = 1 bpp (e.g. A_8, G_8)
- * 2     = 3 bpp, aligned (e.g. 888)
- * 3     = 4 bpp, aligned (e.g. 8888)
- * 4-6   = 2 bpp, not aligned (e.g. 565, 4444, 5551)
- * 7     = undefined yuv
- * 9     = 2 bpp, aligned
- * 10     = undefined
- * 11     = undefined
- * 12    = 3 bpp, not aligned
- * 13    = 4 bpp, not aligned (e.g. 2101010)
- * 14-15 = undefined
- */
-int
-_cogl_pixel_format_get_bytes_per_pixel (CoglPixelFormat format)
+uint8_t
+cogl_pixel_format_get_bytes_per_pixel_simple (CoglPixelFormat format)
 {
   size_t i;
 
   for (i = 0; i < G_N_ELEMENTS (format_info_table); i++)
     {
       if (format_info_table[i].cogl_format == format)
-        return format_info_table[i].bpp;
+        {
+          g_return_val_if_fail (format_info_table[i].n_planes == 1, 0);
+          return format_info_table[i].bpp[0];
+        }
+    }
+
+  g_assert_not_reached ();
+}
+
+void
+cogl_pixel_format_get_bytes_per_pixel (CoglPixelFormat format, uint8_t *bpp_out)
+{
+  size_t i, j;
+
+  for (i = 0; i < G_N_ELEMENTS (format_info_table); i++)
+    {
+      if (format_info_table[i].cogl_format != format)
+        continue;
+
+      for (j = 0; j < format_info_table[i].n_planes; j++)
+        bpp_out[j] = format_info_table[i].bpp[j];
+      return;
     }
 
   g_assert_not_reached ();
 }
 
 /* Note: this also refers to the mapping defined above for
- * _cogl_pixel_format_get_bytes_per_pixel() */
+ * cogl_pixel_format_get_bytes_per_pixel() */
 gboolean
 _cogl_pixel_format_is_endian_dependant (CoglPixelFormat format)
 {
@@ -295,6 +721,44 @@ _cogl_pixel_format_is_endian_dependant (CoglPixelFormat format)
   return aligned;
 }
 
+uint8_t
+cogl_pixel_format_get_n_planes (CoglPixelFormat format)
+{
+  size_t i;
+
+  for (i = 0; i < G_N_ELEMENTS (format_info_table); i++)
+    {
+      if (format_info_table[i].cogl_format == format)
+        return format_info_table[i].n_planes;
+    }
+
+  g_assert_not_reached ();
+}
+
+void
+cogl_pixel_format_get_subsampling_factors (CoglPixelFormat format,
+                                           uint8_t *horizontal_factors,
+                                           uint8_t *vertical_factors)
+{
+  size_t i, j;
+
+  for (i = 0; i < G_N_ELEMENTS (format_info_table); i++)
+    {
+      if (format_info_table[i].cogl_format != format)
+        continue;
+
+      for (j = 0; j < format_info_table[i].n_planes; j++)
+        {
+          horizontal_factors[j] = format_info_table[i].hsub[j];
+          vertical_factors[j] = format_info_table[i].vsub[j];
+        }
+
+      return;
+    }
+
+  g_assert_not_reached ();
+}
+
 const char *
 cogl_pixel_format_to_string (CoglPixelFormat format)
 {
@@ -308,3 +772,51 @@ cogl_pixel_format_to_string (CoglPixelFormat format)
 
   g_assert_not_reached ();
 }
+
+void
+cogl_pixel_format_get_subformats (CoglPixelFormat  format,
+                                  CoglPixelFormat *formats_out)
+{
+  size_t i, j;
+
+  for (i = 0; i < G_N_ELEMENTS (format_info_table); i++)
+    {
+      if (format_info_table[i].cogl_format != format)
+        continue;
+
+      for (j = 0; j < format_info_table[i].n_planes; j++)
+        formats_out[j] = format_info_table[i].subformats[j];
+      return;
+    }
+
+  g_assert_not_reached ();
+}
+
+void
+cogl_pixel_format_get_cogl_components (CoglPixelFormat  format,
+                                       guint           *components_out)
+{
+  switch (format)
+    {
+    case COGL_PIXEL_FORMAT_NV12:
+      components_out[0] = COGL_TEXTURE_COMPONENTS_R;
+      components_out[1] = COGL_TEXTURE_COMPONENTS_RG;
+      break;
+    case COGL_PIXEL_FORMAT_NV21:
+      components_out[0] = COGL_TEXTURE_COMPONENTS_R;
+      components_out[1] = COGL_TEXTURE_COMPONENTS_RG;
+      break;
+    case COGL_PIXEL_FORMAT_YUV422:
+      components_out[0] = COGL_TEXTURE_COMPONENTS_R;
+      components_out[1] = COGL_TEXTURE_COMPONENTS_R;
+      components_out[2] = COGL_TEXTURE_COMPONENTS_R;
+      break;
+    case COGL_PIXEL_FORMAT_YUV444:
+      components_out[0] = COGL_TEXTURE_COMPONENTS_R;
+      components_out[1] = COGL_TEXTURE_COMPONENTS_R;
+      components_out[2] = COGL_TEXTURE_COMPONENTS_R;
+      break;
+    default:
+      components_out[0] = COGL_TEXTURE_COMPONENTS_RGBA;
+    }
+}
diff --git a/cogl/cogl/cogl-pixel-format.h b/cogl/cogl/cogl-pixel-format.h
index 6b015f9e2..48b332a84 100644
--- a/cogl/cogl/cogl-pixel-format.h
+++ b/cogl/cogl/cogl-pixel-format.h
@@ -145,7 +145,7 @@ G_BEGIN_DECLS
  * @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_R_8: Single red component, 8 bits
  * @COGL_PIXEL_FORMAT_RGB_888: RGB, 24 bits
  * @COGL_PIXEL_FORMAT_BGR_888: BGR, 24 bits
@@ -167,6 +167,35 @@ G_BEGIN_DECLS
  * @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_XRGB8888_A8: 2 planes: 1 RGB-plane (64-bit), 1 alpha-plane
+ * @COGL_PIXEL_FORMAT_XBGR8888_A8: 2 planes: 1 BGR-plane (64-bit), 1 alpha-plane
+ * @COGL_PIXEL_FORMAT_RGBX8888_A8: 2 planes: 1 RGB-plane (64-bit), 1 alpha-plane
+ * @COGL_PIXEL_FORMAT_BGRX8888_A8: 2 planes: 1 BGR-plane (64-bit), 1 alpha-plane
+ * @COGL_PIXEL_FORMAT_RGB888_A8: 2 planes: 1 RGB-plane (32-bit), 1 alpha-plane
+ * @COGL_PIXEL_FORMAT_BGR888_A8: 2 planes: 1 BGR-plane (32-bit), 1 alpha-plane
+ * @COGL_PIXEL_FORMAT_RGB565_A8: 2 planes: 1 RGB-plane (16-bit), 1 alpha-plane
+ * @COGL_PIXEL_FORMAT_BGR565_A8: 2 planes: 1 BGR-plane (16-bit), 1 alpha-plane
+ * @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
@@ -230,20 +259,83 @@ 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_XRGB8888_A8 = ( 6 << 24),
+  COGL_PIXEL_FORMAT_XBGR8888_A8 = ( 7 << 24),
+  COGL_PIXEL_FORMAT_RGBX8888_A8 = ( 8 << 24),
+  COGL_PIXEL_FORMAT_BGRX8888_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_MAX_PLANES:
+ *
+ * The maximum number of planes
+ */
+#define COGL_PIXEL_FORMAT_MAX_PLANES (4)
+
 /*
- * _cogl_pixel_format_get_bytes_per_pixel:
+ * cogl_pixel_format_get_bytes_per_pixel:
+ * @format: a #CoglPixelFormat
+ * @bpp_out: (inout): A buffer that will be filled with the bytes-per-pixel for each
+ * plane
+ *
+ * Queries how many bytes a pixel of the given @format takes in each plane.
+ *
+ * Returns: The no. of bytes in one pixel of the given single-plane @format.
+ */
+void
+cogl_pixel_format_get_bytes_per_pixel (CoglPixelFormat format,
+                                       uint8_t *bpp_out);
+
+/*
+ * cogl_pixel_format_get_bytes_per_pixel_simple:
  * @format: a #CoglPixelFormat
  *
  * Queries how many bytes a pixel of the given @format takes.
  *
- * Return value: The number of bytes taken for a pixel of the given
- *               @format.
+ * Returns: The no. of bytes in one pixel of the given single-plane @format.
  */
-int
-_cogl_pixel_format_get_bytes_per_pixel (CoglPixelFormat format);
+uint8_t
+cogl_pixel_format_get_bytes_per_pixel_simple (CoglPixelFormat format);
 
 /*
  * _cogl_pixel_format_has_aligned_components:
@@ -284,6 +376,26 @@ _cogl_pixel_format_is_endian_dependant (CoglPixelFormat format);
 #define COGL_PIXEL_FORMAT_CAN_HAVE_PREMULT(format) \
   (((format) & COGL_A_BIT) && (format) != COGL_PIXEL_FORMAT_A_8)
 
+/**
+ * cogl_pixel_format_get_n_planes:
+ * @format: The format for which to get the number of planes
+ *
+ * Returns the number of planes the given CoglPixelFormat specifies.
+ */
+uint8_t
+cogl_pixel_format_get_n_planes (CoglPixelFormat format);
+
+/**
+ * cogl_pixel_format_get_subsampling_factors:
+ * @format: The format to get the subsampling factors from.
+ *
+ * Returns the subsampling in both the horizontal as the vertical direction.
+ */
+void
+cogl_pixel_format_get_subsampling_factors (CoglPixelFormat format,
+                                           uint8_t *horizontal_factors,
+                                           uint8_t *vertical_factors);
+
 /**
  * cogl_pixel_format_to_string:
  * @format: a #CoglPixelFormat
@@ -295,6 +407,14 @@ _cogl_pixel_format_is_endian_dependant (CoglPixelFormat format);
 const char *
 cogl_pixel_format_to_string (CoglPixelFormat format);
 
+void
+cogl_pixel_format_get_subformats (CoglPixelFormat  format,
+                                  CoglPixelFormat *formats_out);
+
+void
+cogl_pixel_format_get_cogl_components (CoglPixelFormat format,
+                                       guint *components_out);
+
 G_END_DECLS
 
 #endif /* __COGL_PIXEL_FORMAT_H__ */
diff --git a/cogl/cogl/cogl-texture-2d-sliced.c b/cogl/cogl/cogl-texture-2d-sliced.c
index c651557a8..30fdfb3f5 100644
--- a/cogl/cogl/cogl-texture-2d-sliced.c
+++ b/cogl/cogl/cogl-texture-2d-sliced.c
@@ -163,7 +163,7 @@ _cogl_texture_2d_sliced_allocate_waste_buffer (CoglTexture2DSliced *tex_2ds,
                                 tex_2ds->slice_y_spans->len - 1);
   if (last_x_span->waste > 0 || last_y_span->waste > 0)
     {
-      int bpp = _cogl_pixel_format_get_bytes_per_pixel (format);
+      int bpp = cogl_pixel_format_get_bytes_per_pixel_simple (format);
       CoglSpan  *first_x_span
         = &g_array_index (tex_2ds->slice_x_spans, CoglSpan, 0);
       CoglSpan  *first_y_span
@@ -209,7 +209,7 @@ _cogl_texture_2d_sliced_set_waste (CoglTexture2DSliced *tex_2ds,
     {
       int bmp_rowstride = cogl_bitmap_get_rowstride (source_bmp);
       CoglPixelFormat source_format = cogl_bitmap_get_format (source_bmp);
-      int bpp = _cogl_pixel_format_get_bytes_per_pixel (source_format);
+      int bpp = cogl_pixel_format_get_bytes_per_pixel_simple (source_format);
       uint8_t *bmp_data;
       const uint8_t *src;
       uint8_t *dst;
@@ -972,7 +972,7 @@ cogl_texture_2d_sliced_new_from_data (CoglContext *ctx,
 
   /* Rowstride from width if not given */
   if (rowstride == 0)
-    rowstride = width * _cogl_pixel_format_get_bytes_per_pixel (format);
+    rowstride = width * cogl_pixel_format_get_bytes_per_pixel_simple (format);
 
   /* Wrap the data into a bitmap */
   bmp = cogl_bitmap_new_for_data (ctx,
diff --git a/cogl/cogl/cogl-texture-2d.c b/cogl/cogl/cogl-texture-2d.c
index 05cfff42a..d56538557 100644
--- a/cogl/cogl/cogl-texture-2d.c
+++ b/cogl/cogl/cogl-texture-2d.c
@@ -207,7 +207,7 @@ cogl_texture_2d_new_from_data (CoglContext *ctx,
 
   /* Rowstride from width if not given */
   if (rowstride == 0)
-    rowstride = width * _cogl_pixel_format_get_bytes_per_pixel (format);
+    rowstride = width * cogl_pixel_format_get_bytes_per_pixel_simple (format);
 
   /* Wrap the data into a bitmap */
   bmp = cogl_bitmap_new_for_data (ctx,
diff --git a/cogl/cogl/cogl-texture.c b/cogl/cogl/cogl-texture.c
index f57d4a770..299eb2ffe 100644
--- a/cogl/cogl/cogl-texture.c
+++ b/cogl/cogl/cogl-texture.c
@@ -430,10 +430,14 @@ _cogl_texture_set_region (CoglTexture *texture,
   gboolean ret;
 
   g_return_val_if_fail (format != COGL_PIXEL_FORMAT_ANY, FALSE);
+  g_return_val_if_fail (cogl_pixel_format_get_n_planes (format) == 1, FALSE);
 
   /* Rowstride from width if none specified */
   if (rowstride == 0)
-    rowstride = _cogl_pixel_format_get_bytes_per_pixel (format) * width;
+    {
+      uint8_t bpp = cogl_pixel_format_get_bytes_per_pixel_simple (format);
+      rowstride = bpp * width;
+    }
 
   /* Init source bitmap */
   source_bmp = cogl_bitmap_new_for_data (ctx,
@@ -471,7 +475,7 @@ cogl_texture_set_region (CoglTexture *texture,
 {
   GError *ignore_error = NULL;
   const uint8_t *first_pixel;
-  int bytes_per_pixel = _cogl_pixel_format_get_bytes_per_pixel (format);
+  int bytes_per_pixel = cogl_pixel_format_get_bytes_per_pixel_simple (format);
   gboolean status;
 
   /* Rowstride from width if none specified */
@@ -609,7 +613,7 @@ get_texture_bits_via_copy (CoglTexture *texture,
   full_tex_width = cogl_texture_get_width (texture);
   full_tex_height = cogl_texture_get_height (texture);
 
-  bpp = _cogl_pixel_format_get_bytes_per_pixel (dst_format);
+  bpp = cogl_pixel_format_get_bytes_per_pixel_simple (dst_format);
 
   full_rowstride = bpp * full_tex_width;
   full_bits = g_malloc (full_rowstride * full_tex_height);
@@ -658,7 +662,7 @@ texture_get_cb (CoglTexture *subtexture,
   CoglTextureGetData *tg_data = user_data;
   CoglTexture *meta_texture = tg_data->meta_texture;
   CoglPixelFormat closest_format = cogl_bitmap_get_format (tg_data->target_bmp);
-  int bpp = _cogl_pixel_format_get_bytes_per_pixel (closest_format);
+  int bpp = cogl_pixel_format_get_bytes_per_pixel_simple (closest_format);
   unsigned int rowstride = cogl_bitmap_get_rowstride (tg_data->target_bmp);
   int subtexture_width = cogl_texture_get_width (subtexture);
   int subtexture_height = cogl_texture_get_height (subtexture);
@@ -748,7 +752,7 @@ cogl_texture_get_data (CoglTexture *texture,
   tex_height = cogl_texture_get_height (texture);
 
   /* Rowstride from texture width if none specified */
-  bpp = _cogl_pixel_format_get_bytes_per_pixel (format);
+  bpp = cogl_pixel_format_get_bytes_per_pixel_simple (format);
   if (rowstride == 0)
     rowstride = tex_width * bpp;
 
diff --git a/cogl/cogl/cogl.c b/cogl/cogl/cogl.c
index bf46ea055..fc66065a6 100644
--- a/cogl/cogl/cogl.c
+++ b/cogl/cogl/cogl.c
@@ -330,7 +330,7 @@ cogl_read_pixels (int x,
                   CoglPixelFormat format,
                   uint8_t *pixels)
 {
-  int bpp = _cogl_pixel_format_get_bytes_per_pixel (format);
+  int bpp = cogl_pixel_format_get_bytes_per_pixel_simple (format);
   CoglBitmap *bitmap;
 
   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
diff --git a/cogl/cogl/deprecated/cogl-auto-texture.c b/cogl/cogl/deprecated/cogl-auto-texture.c
index a13020c0d..0503abcbf 100644
--- a/cogl/cogl/deprecated/cogl-auto-texture.c
+++ b/cogl/cogl/deprecated/cogl-auto-texture.c
@@ -148,7 +148,7 @@ _cogl_texture_new_from_data (CoglContext *ctx,
 
   /* Rowstride from width if not given */
   if (rowstride == 0)
-    rowstride = width * _cogl_pixel_format_get_bytes_per_pixel (format);
+    rowstride = width * cogl_pixel_format_get_bytes_per_pixel_simple (format);
 
   /* Wrap the data into a bitmap */
   bmp = cogl_bitmap_new_for_data (ctx,
diff --git a/cogl/cogl/driver/gl/cogl-framebuffer-gl.c b/cogl/cogl/driver/gl/cogl-framebuffer-gl.c
index b8fd2f689..07b971f86 100644
--- a/cogl/cogl/driver/gl/cogl-framebuffer-gl.c
+++ b/cogl/cogl/driver/gl/cogl-framebuffer-gl.c
@@ -1303,7 +1303,7 @@ _cogl_framebuffer_gl_read_pixels_into_bitmap (CoglFramebuffer *framebuffer,
       if (!tmp_bmp)
         goto EXIT;
 
-      bpp = _cogl_pixel_format_get_bytes_per_pixel (read_format);
+      bpp = cogl_pixel_format_get_bytes_per_pixel_simple (read_format);
       rowstride = cogl_bitmap_get_rowstride (tmp_bmp);
 
       ctx->texture_driver->prep_gl_for_pixels_download (ctx,
@@ -1360,7 +1360,7 @@ _cogl_framebuffer_gl_read_pixels_into_bitmap (CoglFramebuffer *framebuffer,
       else
         shared_bmp = cogl_object_ref (bitmap);
 
-      bpp = _cogl_pixel_format_get_bytes_per_pixel (bmp_format);
+      bpp = cogl_pixel_format_get_bytes_per_pixel_simple (bmp_format);
 
       ctx->texture_driver->prep_gl_for_pixels_download (ctx,
                                                         rowstride,
diff --git a/cogl/cogl/driver/gl/cogl-texture-2d-gl.c b/cogl/cogl/driver/gl/cogl-texture-2d-gl.c
index 57d40f3a3..c17a66546 100644
--- a/cogl/cogl/driver/gl/cogl-texture-2d-gl.c
+++ b/cogl/cogl/driver/gl/cogl-texture-2d-gl.c
@@ -250,7 +250,7 @@ allocate_from_bitmap (CoglTexture2D *tex_2d,
       if (data)
         {
           memcpy (tex_2d->first_pixel.data, data,
-                  _cogl_pixel_format_get_bytes_per_pixel (format));
+                  cogl_pixel_format_get_bytes_per_pixel_simple (format));
           _cogl_bitmap_unmap (upload_bmp);
         }
       else
@@ -259,7 +259,7 @@ allocate_from_bitmap (CoglTexture2D *tex_2d,
                      "glGenerateMipmap fallback");
           g_error_free (ignore);
           memset (tex_2d->first_pixel.data, 0,
-                  _cogl_pixel_format_get_bytes_per_pixel (format));
+                  cogl_pixel_format_get_bytes_per_pixel_simple (format));
         }
     }
 
@@ -789,7 +789,7 @@ _cogl_texture_2d_gl_copy_from_bitmap (CoglTexture2D *tex_2d,
       uint8_t *data =
         _cogl_bitmap_map (upload_bmp, COGL_BUFFER_ACCESS_READ, 0, &ignore);
       CoglPixelFormat bpp =
-        _cogl_pixel_format_get_bytes_per_pixel (upload_format);
+        cogl_pixel_format_get_bytes_per_pixel_simple (upload_format);
 
       tex_2d->first_pixel.gl_format = gl_format;
       tex_2d->first_pixel.gl_type = gl_type;
@@ -852,7 +852,7 @@ _cogl_texture_2d_gl_get_data (CoglTexture2D *tex_2d,
   GLenum gl_format;
   GLenum gl_type;
 
-  bpp = _cogl_pixel_format_get_bytes_per_pixel (format);
+  bpp = cogl_pixel_format_get_bytes_per_pixel_simple (format);
 
   ctx->driver_vtable->pixel_format_to_gl (ctx,
                                           format,
diff --git a/cogl/cogl/driver/gl/gl/cogl-driver-gl.c b/cogl/cogl/driver/gl/gl/cogl-driver-gl.c
index bb42e7910..b0402b7ec 100644
--- a/cogl/cogl/driver/gl/gl/cogl-driver-gl.c
+++ b/cogl/cogl/driver/gl/gl/cogl-driver-gl.c
@@ -260,7 +260,37 @@ _cogl_driver_pixel_format_to_gl (CoglContext     *context,
       break;
 
     case COGL_PIXEL_FORMAT_ANY:
+    /* No support for YUV or multi-plane formats */
     case COGL_PIXEL_FORMAT_YUV:
+    case COGL_PIXEL_FORMAT_YUYV:
+    case COGL_PIXEL_FORMAT_YVYU:
+    case COGL_PIXEL_FORMAT_UYVY:
+    case COGL_PIXEL_FORMAT_VYUY:
+    case COGL_PIXEL_FORMAT_AYUV:
+    case COGL_PIXEL_FORMAT_XRGB8888_A8:
+    case COGL_PIXEL_FORMAT_XBGR8888_A8:
+    case COGL_PIXEL_FORMAT_RGBX8888_A8:
+    case COGL_PIXEL_FORMAT_BGRX8888_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:
+    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:
       g_assert_not_reached ();
       break;
     }
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 1505a2af7..42082871e 100644
--- a/cogl/cogl/driver/gl/gl/cogl-texture-driver-gl.c
+++ b/cogl/cogl/driver/gl/gl/cogl-texture-driver-gl.c
@@ -196,7 +196,7 @@ _cogl_texture_driver_upload_subregion_to_gl (CoglContext *ctx,
   GLuint gl_handle;
   uint8_t *data;
   CoglPixelFormat source_format = cogl_bitmap_get_format (source_bmp);
-  int bpp = _cogl_pixel_format_get_bytes_per_pixel (source_format);
+  int bpp = cogl_pixel_format_get_bytes_per_pixel_simple (source_format);
   gboolean status = TRUE;
   GError *internal_error = NULL;
   int level_width;
@@ -302,7 +302,7 @@ _cogl_texture_driver_upload_to_gl (CoglContext *ctx,
 {
   uint8_t *data;
   CoglPixelFormat source_format = cogl_bitmap_get_format (source_bmp);
-  int bpp = _cogl_pixel_format_get_bytes_per_pixel (source_format);
+  int bpp = cogl_pixel_format_get_bytes_per_pixel_simple (source_format);
   gboolean status = TRUE;
   GError *internal_error = NULL;
 
diff --git a/cogl/cogl/driver/gl/gles/cogl-driver-gles.c b/cogl/cogl/driver/gl/gles/cogl-driver-gles.c
index 829d2a38b..9646e4516 100644
--- a/cogl/cogl/driver/gl/gles/cogl-driver-gles.c
+++ b/cogl/cogl/driver/gl/gles/cogl-driver-gles.c
@@ -198,7 +198,37 @@ _cogl_driver_pixel_format_to_gl (CoglContext     *context,
       break;
 
     case COGL_PIXEL_FORMAT_ANY:
+    /* No support for YUV or multi-plane formats */
     case COGL_PIXEL_FORMAT_YUV:
+    case COGL_PIXEL_FORMAT_YUYV:
+    case COGL_PIXEL_FORMAT_YVYU:
+    case COGL_PIXEL_FORMAT_UYVY:
+    case COGL_PIXEL_FORMAT_VYUY:
+    case COGL_PIXEL_FORMAT_AYUV:
+    case COGL_PIXEL_FORMAT_XRGB8888_A8:
+    case COGL_PIXEL_FORMAT_XBGR8888_A8:
+    case COGL_PIXEL_FORMAT_RGBX8888_A8:
+    case COGL_PIXEL_FORMAT_BGRX8888_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:
+    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:
       g_assert_not_reached ();
       break;
     }
diff --git a/cogl/cogl/driver/gl/gles/cogl-texture-driver-gles.c 
b/cogl/cogl/driver/gl/gles/cogl-texture-driver-gles.c
index 22130784b..21e6cfa78 100644
--- a/cogl/cogl/driver/gl/gles/cogl-texture-driver-gles.c
+++ b/cogl/cogl/driver/gl/gles/cogl-texture-driver-gles.c
@@ -152,7 +152,7 @@ prepare_bitmap_alignment_for_upload (CoglContext *ctx,
                                      GError **error)
 {
   CoglPixelFormat format = cogl_bitmap_get_format (src_bmp);
-  int bpp = _cogl_pixel_format_get_bytes_per_pixel (format);
+  int bpp = cogl_pixel_format_get_bytes_per_pixel_simple (format);
   int src_rowstride = cogl_bitmap_get_rowstride (src_bmp);
   int width = cogl_bitmap_get_width (src_bmp);
   int alignment = 1;
@@ -195,7 +195,7 @@ _cogl_texture_driver_upload_subregion_to_gl (CoglContext *ctx,
   GLuint gl_handle;
   uint8_t *data;
   CoglPixelFormat source_format = cogl_bitmap_get_format (source_bmp);
-  int bpp = _cogl_pixel_format_get_bytes_per_pixel (source_format);
+  int bpp = cogl_pixel_format_get_bytes_per_pixel_simple (source_format);
   CoglBitmap *slice_bmp;
   int rowstride;
   gboolean status = TRUE;
@@ -337,7 +337,7 @@ _cogl_texture_driver_upload_to_gl (CoglContext *ctx,
                                    GError **error)
 {
   CoglPixelFormat source_format = cogl_bitmap_get_format (source_bmp);
-  int bpp = _cogl_pixel_format_get_bytes_per_pixel (source_format);
+  int bpp = cogl_pixel_format_get_bytes_per_pixel_simple (source_format);
   int rowstride;
   int bmp_width = cogl_bitmap_get_width (source_bmp);
   int bmp_height = cogl_bitmap_get_height (source_bmp);
diff --git a/cogl/cogl/libmutter-cogl.map.in b/cogl/cogl/libmutter-cogl.map.in
index 12ae32d6d..8f8a2eaf6 100644
--- a/cogl/cogl/libmutter-cogl.map.in
+++ b/cogl/cogl/libmutter-cogl.map.in
@@ -42,7 +42,6 @@ global:
   _cogl_framebuffer_winsys_update_size;
   _cogl_winsys_egl_make_current;
   _cogl_winsys_egl_ensure_current;
-  _cogl_pixel_format_get_bytes_per_pixel*;
   _cogl_system_error_quark;
   _cogl_util_next_p2;
   @unit_tests_symbols@
diff --git a/cogl/cogl/meson.build b/cogl/cogl/meson.build
index dab2674c4..513fa9c77 100644
--- a/cogl/cogl/meson.build
+++ b/cogl/cogl/meson.build
@@ -89,6 +89,7 @@ cogl_headers = [
   'cogl-pipeline-state.h',
   'cogl-pipeline-layer-state.h',
   'cogl-pixel-format.h',
+  'cogl-pixel-format-conversion.h',
   'cogl-primitives.h',
   'cogl-texture.h',
   'cogl-texture-2d.h',
@@ -249,10 +250,11 @@ cogl_sources = [
   'cogl-bitmap-pixbuf.c',
   'cogl-clip-stack.h',
   'cogl-clip-stack.c',
-  'cogl-feature-private.h',
-  'cogl-feature-private.c',
   'cogl-color-private.h',
   'cogl-color.c',
+  'cogl-pixel-format-conversion.c',
+  'cogl-feature-private.c',
+  'cogl-feature-private.h',
   'cogl-buffer-private.h',
   'cogl-buffer.c',
   'cogl-pixel-buffer-private.h',
diff --git a/cogl/cogl/winsys/cogl-texture-pixmap-x11.c b/cogl/cogl/winsys/cogl-texture-pixmap-x11.c
index df8295685..f1e313104 100644
--- a/cogl/cogl/winsys/cogl-texture-pixmap-x11.c
+++ b/cogl/cogl/winsys/cogl-texture-pixmap-x11.c
@@ -730,7 +730,7 @@ _cogl_texture_pixmap_x11_update_image_texture (CoglTexturePixmapX11 *tex_pixmap)
                                         image->bits_per_pixel,
                                         image->byte_order == LSBFirst);
 
-  bpp = _cogl_pixel_format_get_bytes_per_pixel (image_format);
+  bpp = cogl_pixel_format_get_bytes_per_pixel_simple (image_format);
   offset = image->bytes_per_line * src_y + bpp * src_x;
 
   _cogl_texture_set_region (tex_pixmap->tex,
diff --git a/src/wayland/meta-wayland-buffer.c b/src/wayland/meta-wayland-buffer.c
index f45679d3a..0f191a0d8 100644
--- a/src/wayland/meta-wayland-buffer.c
+++ b/src/wayland/meta-wayland-buffer.c
@@ -489,7 +489,7 @@ process_shm_buffer_damage (MetaWaylandBuffer *buffer,
       cairo_rectangle_int_t rect;
 
       shm_buffer_get_cogl_pixel_format (shm_buffer, &format, NULL);
-      bpp = _cogl_pixel_format_get_bytes_per_pixel (format);
+      bpp = cogl_pixel_format_get_bytes_per_pixel_simple (format);
       cairo_region_get_rectangle (region, i, &rect);
 
       if (!_cogl_texture_set_region (texture,


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