[mutter/wip/nielsdg/add-yuv-support: 47/47] WIP: wayland: add basic support for non-RGBA textures
- From: Niels De Graef <nielsdg src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [mutter/wip/nielsdg/add-yuv-support: 47/47] WIP: wayland: add basic support for non-RGBA textures
- Date: Wed, 24 Apr 2019 15:32:48 +0000 (UTC)
commit 41fd402e18106cfd9da5f994b430cb5b203d53fd
Author: Niels De Graef <Niels DeGraef barco com>
Date: Wed Nov 14 12:22:02 2018 +0100
WIP: wayland: add basic support for non-RGBA 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. It also provides support
for CoglSnippets which can convert the colorspace if necessary.
What changes are in this commit:
* Introduce a new CoglMultiPlaneTexture object. Right now it is not
implemented as a CoglTexture to prevent any confusion (but it is
somewhat related to CoglMetaTexture)
* 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
different kind of buffer we can receive from wayland.
Acknowledgements
* There was a lot of prior art already done by the authors of Weston,
CoglGstVideoSink and ClutterGstSink
* My employer Barco for allowing me to work on this
cogl/cogl/cogl-bitmap-conversion.c | 1 +
cogl/cogl/cogl-multi-plane-texture.c | 252 ++++++++++++++++++
cogl/cogl/cogl-multi-plane-texture.h | 205 +++++++++++++++
cogl/cogl/cogl-pixel-format-conversion.c | 163 ++++++++++++
cogl/cogl/cogl-pixel-format-conversion.h | 92 +++++++
cogl/cogl/cogl-types.h | 118 ++++++++-
cogl/cogl/cogl.c | 300 +++++++++++++++++++++
cogl/cogl/cogl.h | 2 +
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 | 8 +-
src/compositor/meta-shaped-texture-private.h | 2 +-
src/compositor/meta-shaped-texture.c | 242 +++++++++++------
src/compositor/meta-surface-actor-x11.c | 11 +-
src/compositor/meta-surface-actor.c | 10 +-
src/meta/meta-shaped-texture.h | 2 +-
src/wayland/meta-wayland-buffer.c | 334 ++++++++++++++++--------
src/wayland/meta-wayland-buffer.h | 16 +-
src/wayland/meta-wayland-cursor-surface.c | 9 +-
src/wayland/meta-wayland-dma-buf.c | 231 +++++++++++-----
src/wayland/meta-wayland-dma-buf.h | 8 +-
src/wayland/meta-wayland-egl-stream.c | 20 +-
src/wayland/meta-wayland-egl-stream.h | 4 +-
src/wayland/meta-wayland-shell-surface.c | 6 +-
src/wayland/meta-wayland-surface.c | 8 +-
src/wayland/meta-wayland-surface.h | 4 +-
src/wayland/meta-wayland.c | 24 ++
28 files changed, 1773 insertions(+), 313 deletions(-)
---
diff --git a/cogl/cogl/cogl-bitmap-conversion.c b/cogl/cogl/cogl-bitmap-conversion.c
index 73cf3153e..03c16c4ae 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..6d7c50009
--- /dev/null
+++ b/cogl/cogl/cogl-multi-plane-texture.c
@@ -0,0 +1,252 @@
+/*
+ * 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"
+#include "cogl-texture-private.h"
+#include "cogl-texture-2d-sliced.h"
+
+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]);
+}
+
+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;
+}
+
+CoglMultiPlaneTexture *
+cogl_multi_plane_texture_new_from_bitmaps (CoglPixelFormat format,
+ CoglBitmap **bitmaps, guint n_planes,
+ GError **error)
+{
+ guint i = 0;
+ CoglMultiPlaneTexture *self = g_slice_new0 (CoglMultiPlaneTexture);
+
+ _cogl_multi_plane_texture_object_new (self);
+
+ self->format = format;
+ self->n_planes = n_planes;
+ self->planes = g_malloc (sizeof (CoglTexture *) * n_planes);
+
+ /* XXX convert to appropriate textures here */
+ for (i = 0; i < n_planes; i++)
+ {
+ CoglTexture *plane;
+
+ if (format == COGL_PIXEL_FORMAT_NV12)
+ {
+ /* Issue here: the data is inside the A coordinate, rather than the X coordinate */
+ if (i == 0)
+ _cogl_bitmap_set_format (bitmaps[i], COGL_PIXEL_FORMAT_G_8);
+ else
+ _cogl_bitmap_set_format (bitmaps[i], COGL_PIXEL_FORMAT_RG_88);
+ }
+
+ plane = COGL_TEXTURE (cogl_texture_2d_new_from_bitmap (bitmaps[i]));
+
+ if (format == COGL_PIXEL_FORMAT_NV12)
+ {
+ if (i == 0)
+ {
+ _cogl_texture_set_internal_format (plane, COGL_PIXEL_FORMAT_G_8);
+ _cogl_bitmap_set_format (bitmaps[i], COGL_PIXEL_FORMAT_G_8);
+ }
+ else
+ {
+ _cogl_texture_set_internal_format (plane, COGL_PIXEL_FORMAT_RG_88);
+ _cogl_bitmap_set_format (bitmaps[i], COGL_PIXEL_FORMAT_RG_88);
+ }
+ } else {
+ /* XXX Let's break everyting for non RGBA */
+ cogl_texture_set_components (plane, COGL_TEXTURE_COMPONENTS_RGBA);
+ }
+
+ if (!cogl_texture_allocate (plane, error))
+ {
+ g_clear_pointer (&plane, cogl_object_unref);
+
+ /* There's a chance we failed due to the buffer being NPOT size.
+ * If so, try again with CoglTexture2DSliced (which does support this) */
+ if (g_error_matches (*error,
+ COGL_TEXTURE_ERROR,
+ COGL_TEXTURE_ERROR_SIZE))
+ {
+ CoglTexture2DSliced *plane_sliced;
+
+ g_clear_error (error);
+
+ plane_sliced =
+ cogl_texture_2d_sliced_new_from_bitmap (bitmaps[i],
+ COGL_TEXTURE_MAX_WASTE);
+ plane = COGL_TEXTURE (plane_sliced);
+ if (format == COGL_PIXEL_FORMAT_NV12)
+ {
+ if (i == 0)
+ {
+ _cogl_texture_set_internal_format (plane, COGL_PIXEL_FORMAT_G_8);
+ _cogl_bitmap_set_format (bitmaps[i], COGL_PIXEL_FORMAT_G_8);
+ }
+ else
+ {
+ _cogl_texture_set_internal_format (plane, COGL_PIXEL_FORMAT_RG_88);
+ _cogl_bitmap_set_format (bitmaps[i], COGL_PIXEL_FORMAT_RG_88);
+ }
+ } else {
+ /* XXX Let's break everyting for non RGBA */
+ cogl_texture_set_components (plane, COGL_TEXTURE_COMPONENTS_RGBA);
+ }
+
+ if (!cogl_texture_allocate (plane, error))
+ cogl_clear_object (&plane);
+ }
+ }
+
+ cogl_object_unref (bitmaps[i]);
+ self->planes[i] = plane;
+ }
+
+
+ return self;
+}
+
+gchar *
+cogl_multi_plane_texture_to_string (CoglMultiPlaneTexture *self)
+{
+ g_autoptr(GString) str = NULL;
+ g_autofree gchar *ret = NULL;
+ guint i;
+
+ str = g_string_new ("");
+ g_string_append_printf (str, "CoglMultiPlaneTexture (%p) {\n", self);
+ g_string_append_printf (str, " .format = %u;\n", self->format);
+ g_string_append_printf (str, " .n_planes = %u;\n", self->n_planes);
+ g_string_append (str, " .planes = {\n");
+
+ for (i = 0; i < self->n_planes; i++)
+ {
+ CoglTexture *plane = self->planes[i];
+
+ g_string_append_printf (str, " (%p) { .format = %u },\n",
+ plane,
+ _cogl_texture_get_format (plane));
+ }
+
+ g_string_append (str, " }\n");
+ g_string_append (str, "}");
+
+ ret = g_string_free (g_steal_pointer (&str), FALSE);
+ return g_steal_pointer (&ret);
+}
diff --git a/cogl/cogl/cogl-multi-plane-texture.h b/cogl/cogl/cogl-multi-plane-texture.h
new file mode 100644
index 000000000..c0d8d89b9
--- /dev/null
+++ b/cogl/cogl/cogl-multi-plane-texture.h
@@ -0,0 +1,205 @@
+/*
+ * 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"
+
+G_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_multi_plane_texture_get_gtype:
+ *
+ * Returns: a #GType that can be used with the GLib type system.
+ */
+GType cogl_multi_plane_texture_get_gtype (void);
+
+/**
+ * cogl_is_multi_plane_texture:
+ * @object: A #CoglObject pointer
+ *
+ * Gets whether the given @object references an existing CoglMultiPlaneTexture.
+ *
+ * Return value: %TRUE if the @object references a #CoglMultiPlaneTexture,
+ * %FALSE otherwise
+ */
+gboolean
+cogl_is_multi_plane_texture (void *object);
+
+/**
+ * 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_new_from_bitmaps:
+ * @format: The format of the new #CoglMultiPlaneTexture
+ * @bitmaps: (transfer full): The planes of the texture, each as a #CoglBitmap
+ * @n_planes: the number of planes the texture contains
+ * @error: (out): Will be set if an error occurred
+ *
+ * Creates a #CoglMultiPlaneTexture from the given bitmaps and makes sure the
+ * planes are uploaded to the GPU.
+ *
+ * Returns: (transfer full): A new #CoglMultiPlaneTexture. Use
+ * cogl_object_unref() when you're done with it.
+ */
+CoglMultiPlaneTexture *
+cogl_multi_plane_texture_new_from_bitmaps (CoglPixelFormat format,
+ CoglBitmap **bitmaps, guint n_planes,
+ GError **error);
+
+/**
+ * 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_to_string:
+ * @self: a #CoglMultiPlaneTexture
+ *
+ * Returns a string representation of @self, useful for debugging purposes.
+ *
+ * Returns: (transfer full): A string representation of @self. Use g_free() when
+ * done with it.
+ */
+gchar * cogl_multi_plane_texture_to_string (CoglMultiPlaneTexture *self);
+
+G_END_DECLS
+
+#endif
diff --git a/cogl/cogl/cogl-pixel-format-conversion.c b/cogl/cogl/cogl-pixel-format-conversion.c
new file mode 100644
index 000000000..3acdd8bb1
--- /dev/null
+++ b/cogl/cogl/cogl-pixel-format-conversion.c
@@ -0,0 +1,163 @@
+/*
+ * 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) \
+ 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"
+
+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"
+ _COGL_YUV_TO_RGBA ("color", "y", "u", "v")
+ " return color;\n"
+ "}\n";
+
+static const gchar yuv_to_rgba_shader[] =
+ "vec4\n"
+ "cogl_yuv_to_rgba (vec2 UV)\n"
+ "{\n"
+ " vec4 color;\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 gchar *global_hook;
+ const gchar *layer_hook;
+
+ switch (format)
+ {
+ case COGL_PIXEL_FORMAT_YUV444:
+ 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 = 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 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-types.h b/cogl/cogl/cogl-types.h
index ca3dbc85d..933475279 100644
--- a/cogl/cogl/cogl-types.h
+++ b/cogl/cogl/cogl-types.h
@@ -225,7 +225,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
@@ -247,6 +247,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
@@ -310,9 +339,94 @@ 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:
+ * @format: The format for which to get the number of planes
+ *
+ * Returns the number of planes the given CoglPixelFormat specifies.
+ */
+guint
+cogl_pixel_format_get_n_planes (CoglPixelFormat format);
+
+/**
+ * cogl_pixel_format_to_string:
+ * @format: The pixel format
+ *
+ * Returns: (transfer none): A stringified version of the given format
+ */
+const gchar *
+cogl_pixel_format_to_string (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,
+ guint *horizontal_factors,
+ guint *vertical_factors);
+
+void
+cogl_pixel_format_get_bits_per_pixel (CoglPixelFormat format, guint *bpp_out);
+
+/**
+ * cogl_pixel_format_get_components:
+ *
+ * XXX make some comments here about (consistently) uploading multiple textures
+ */
+/* void */
+/* cogl_pixel_format_get_texture_components (CoglPixelFormat format, */
+/* CoglTextureComponents *components_out); */
+
/**
* CoglFeatureFlags:
* @COGL_FEATURE_TEXTURE_YUV: ycbcr conversion support
diff --git a/cogl/cogl/cogl.c b/cogl/cogl/cogl.c
index e2f9e0ff9..3d98edbb5 100644
--- a/cogl/cogl/cogl.c
+++ b/cogl/cogl/cogl.c
@@ -765,6 +765,93 @@ _cogl_init (void)
}
}
+typedef struct _CoglPixelFormatInfo {
+ CoglPixelFormat cogl_format;
+ const gchar *format_str;
+ uint8_t n_planes;
+} CoglPixelFormatInfo;
+
+static const CoglPixelFormatInfo format_info_table[] = {
+ { .cogl_format = COGL_PIXEL_FORMAT_ANY, .format_str = "ANY", .n_planes = 1 },
+ { .cogl_format = COGL_PIXEL_FORMAT_A_8, .format_str = "A_8", .n_planes = 1 },
+
+ { .cogl_format = COGL_PIXEL_FORMAT_RGB_565, .format_str = "RGB_565", .n_planes = 1 },
+ { .cogl_format = COGL_PIXEL_FORMAT_RGBA_4444, .format_str = "RGBA_4444", .n_planes = 1 },
+ { .cogl_format = COGL_PIXEL_FORMAT_RGBA_5551, .format_str = "RGBA_5551", .n_planes = 1 },
+ { .cogl_format = COGL_PIXEL_FORMAT_YUV, .format_str = "YUV", .n_planes = 1 },
+ { .cogl_format = COGL_PIXEL_FORMAT_G_8, .format_str = "G_8", .n_planes = 1 },
+
+ { .cogl_format = COGL_PIXEL_FORMAT_RG_88, .format_str = "RG_88", .n_planes = 1 },
+
+ { .cogl_format = COGL_PIXEL_FORMAT_RGB_888, .format_str = "RGB_888", .n_planes = 1 },
+ { .cogl_format = COGL_PIXEL_FORMAT_BGR_888, .format_str = "BGR_888", .n_planes = 1 },
+
+ { .cogl_format = COGL_PIXEL_FORMAT_RGBA_8888, .format_str = "RGBA_8888", .n_planes = 1 },
+ { .cogl_format = COGL_PIXEL_FORMAT_BGRA_8888, .format_str = "BGRA_8888", .n_planes = 1 },
+ { .cogl_format = COGL_PIXEL_FORMAT_ARGB_8888, .format_str = "ARGB_8888", .n_planes = 1 },
+ { .cogl_format = COGL_PIXEL_FORMAT_ABGR_8888, .format_str = "ABGR_8888", .n_planes = 1 },
+
+ { .cogl_format = COGL_PIXEL_FORMAT_RGBA_1010102, .format_str = "RGBA_1010102", .n_planes = 1 },
+ { .cogl_format = COGL_PIXEL_FORMAT_BGRA_1010102, .format_str = "BGRA_1010102", .n_planes = 1 },
+ { .cogl_format = COGL_PIXEL_FORMAT_ARGB_2101010, .format_str = "ARGB_2101010", .n_planes = 1 },
+ { .cogl_format = COGL_PIXEL_FORMAT_ABGR_2101010, .format_str = "ABGR_2101010", .n_planes = 1 },
+
+ { .cogl_format = COGL_PIXEL_FORMAT_RGBA_8888_PRE, .format_str = "RGBA_8888_PRE", .n_planes = 1 },
+ { .cogl_format = COGL_PIXEL_FORMAT_BGRA_8888_PRE, .format_str = "BGRA_8888_PRE", .n_planes = 1 },
+ { .cogl_format = COGL_PIXEL_FORMAT_ARGB_8888_PRE, .format_str = "ARGB_8888_PRE", .n_planes = 1 },
+ { .cogl_format = COGL_PIXEL_FORMAT_ABGR_8888_PRE, .format_str = "ABGR_8888_PRE", .n_planes = 1 },
+ { .cogl_format = COGL_PIXEL_FORMAT_RGBA_4444_PRE, .format_str = "RGBA_4444_PRE", .n_planes = 1 },
+ { .cogl_format = COGL_PIXEL_FORMAT_RGBA_5551_PRE, .format_str = "RGBA_5551_PRE", .n_planes = 1 },
+
+ { .cogl_format = COGL_PIXEL_FORMAT_RGBA_1010102_PRE, .format_str = "RGBA_1010102_PRE", .n_planes = 1 },
+ { .cogl_format = COGL_PIXEL_FORMAT_BGRA_1010102_PRE, .format_str = "BGRA_1010102_PRE", .n_planes = 1 },
+ { .cogl_format = COGL_PIXEL_FORMAT_ARGB_2101010_PRE, .format_str = "ARGB_2101010_PRE", .n_planes = 1 },
+ { .cogl_format = COGL_PIXEL_FORMAT_ABGR_2101010_PRE, .format_str = "ABGR_2101010_PRE", .n_planes = 1 },
+
+ { .cogl_format = COGL_PIXEL_FORMAT_DEPTH_16, .format_str = "DEPTH_16", .n_planes = 1 },
+ { .cogl_format = COGL_PIXEL_FORMAT_DEPTH_32, .format_str = "DEPTH_32", .n_planes = 1 },
+
+ { .cogl_format = COGL_PIXEL_FORMAT_DEPTH_24_STENCIL_8, .format_str = "DEPTH_24_STENCIL_8", .n_planes = 1 },
+
+ /* Packed YUV */
+ { .cogl_format = COGL_PIXEL_FORMAT_YUYV, .format_str = "YUYV", .n_planes = 1 },
+ { .cogl_format = COGL_PIXEL_FORMAT_YVYU, .format_str = "YVYU", .n_planes = 1 },
+ { .cogl_format = COGL_PIXEL_FORMAT_UYVY, .format_str = "UYVY", .n_planes = 1 },
+ { .cogl_format = COGL_PIXEL_FORMAT_VYUY, .format_str = "VYUY", .n_planes = 1 },
+
+ { .cogl_format = COGL_PIXEL_FORMAT_AYUV, .format_str = "AYUV", .n_planes = 1 },
+
+ /* 2 plane RGB + A */
+ { .cogl_format = COGL_PIXEL_FORMAT_XRGB88888_A8, .format_str = "XRGB88888_A8", .n_planes = 2 },
+ { .cogl_format = COGL_PIXEL_FORMAT_XBGR88888_A8, .format_str = "XBGR88888_A8", .n_planes = 2 },
+ { .cogl_format = COGL_PIXEL_FORMAT_RGBX88888_A8, .format_str = "RGBX88888_A8", .n_planes = 2 },
+ { .cogl_format = COGL_PIXEL_FORMAT_BGRX88888_A8, .format_str = "BGRX88888_A8", .n_planes = 2 },
+ { .cogl_format = COGL_PIXEL_FORMAT_RGB888_A8, .format_str = "RGB888_A8", .n_planes = 2 },
+ { .cogl_format = COGL_PIXEL_FORMAT_BGR888_A8, .format_str = "BGR888_A8", .n_planes = 2 },
+ { .cogl_format = COGL_PIXEL_FORMAT_RGB565_A8, .format_str = "RGB565_A8", .n_planes = 2 },
+ { .cogl_format = COGL_PIXEL_FORMAT_BGR565_A8, .format_str = "BGR565_A8", .n_planes = 2 },
+
+ /* 2 plane YUV */
+ { .cogl_format = COGL_PIXEL_FORMAT_NV12, .format_str = "NV12", .n_planes = 2 },
+ { .cogl_format = COGL_PIXEL_FORMAT_NV21, .format_str = "NV21", .n_planes = 2 },
+ { .cogl_format = COGL_PIXEL_FORMAT_NV16, .format_str = "NV16", .n_planes = 2 },
+ { .cogl_format = COGL_PIXEL_FORMAT_NV61, .format_str = "NV61", .n_planes = 2 },
+ { .cogl_format = COGL_PIXEL_FORMAT_NV24, .format_str = "NV24", .n_planes = 2 },
+ { .cogl_format = COGL_PIXEL_FORMAT_NV42, .format_str = "NV42", .n_planes = 2 },
+
+ /* 3 plane YUV */
+ { .cogl_format = COGL_PIXEL_FORMAT_YUV410, .format_str = "YUV410", .n_planes = 3 },
+ { .cogl_format = COGL_PIXEL_FORMAT_YVU410, .format_str = "YVU410", .n_planes = 3 },
+ { .cogl_format = COGL_PIXEL_FORMAT_YUV411, .format_str = "YUV411", .n_planes = 3 },
+ { .cogl_format = COGL_PIXEL_FORMAT_YVU411, .format_str = "YVU411", .n_planes = 3 },
+ { .cogl_format = COGL_PIXEL_FORMAT_YUV420, .format_str = "YUV420", .n_planes = 3 },
+ { .cogl_format = COGL_PIXEL_FORMAT_YVU420, .format_str = "YVU420", .n_planes = 3 },
+ { .cogl_format = COGL_PIXEL_FORMAT_YUV422, .format_str = "YUV422", .n_planes = 3 },
+ { .cogl_format = COGL_PIXEL_FORMAT_YVU422, .format_str = "YVU422", .n_planes = 3 },
+ { .cogl_format = COGL_PIXEL_FORMAT_YUV444, .format_str = "YUV444", .n_planes = 3 },
+ { .cogl_format = COGL_PIXEL_FORMAT_YVU444, .format_str = "YVU444", .n_planes = 3 },
+};
+
/*
* Returns the number of bytes-per-pixel of a given format. The bpp
* can be extracted from the least significant nibble of the pixel
@@ -796,6 +883,43 @@ _cogl_pixel_format_get_bytes_per_pixel (CoglPixelFormat format)
return bpp_lut [format & 0xf];
}
+/*
+ * XXX document.
+ *
+ * XXX lol, this is even per macropixel, not per pixel :D
+ */
+void
+cogl_pixel_format_get_bits_per_pixel (CoglPixelFormat format, guint *bpp_out)
+{
+ /* "old" formats */
+ if (format & (0xff << 24))
+ {
+ switch (format)
+ {
+ case COGL_PIXEL_FORMAT_NV12:
+ case COGL_PIXEL_FORMAT_NV21:
+ bpp_out[0] = 8;
+ bpp_out[1] = 4;
+ break;
+ case COGL_PIXEL_FORMAT_YUV420:
+ case COGL_PIXEL_FORMAT_YVU420:
+ bpp_out[0] = 8;
+ bpp_out[1] = 2;
+ bpp_out[2] = 2;
+ break;
+ }
+ }
+ else
+ {
+ int bpp_lut[] = { 0, 1, 3, 4,
+ 2, 2, 2, 0,
+ 1, 2, 0, 0,
+ 3, 4, 0, 0 };
+
+ bpp_out[0] = 8 * bpp_lut [format & 0xf];
+ }
+}
+
/* Note: this also refers to the mapping defined above for
* _cogl_pixel_format_get_bytes_per_pixel() */
gboolean
@@ -816,3 +940,179 @@ _cogl_pixel_format_is_endian_dependant (CoglPixelFormat format)
return aligned;
}
+
+guint
+cogl_pixel_format_get_n_planes (CoglPixelFormat format)
+{
+ guint 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 ();
+}
+
+const gchar *
+cogl_pixel_format_to_string (CoglPixelFormat format)
+{
+ guint 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].format_str;
+ }
+
+ 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;
+ }
+}
+
+/* void */
+/* cogl_pixel_format_get_texture_components (CoglPixelFormat format, */
+/* CoglTextureComponents *components_out) */
+/* { */
+/* /1* Check for Pre-YUV formats *1/ */
+/* if (format & 0xf000) */
+/* { */
+/* switch (format) */
+/* { */
+/* /1* 2 planes *1/ */
+/* case COGL_PIXEL_FORMAT_NV12: */
+/* case COGL_PIXEL_FORMAT_NV21: */
+/* components_out[0] = COGL_TEXTURE_COMPONENTS_R; */
+/* components_out[1] = COGL_TEXTURE_COMPONENTS_RG; */
+/* break; */
+
+/* /1* XXX TODO *1/ */
+/* /1* case COGL_PIXEL_FORMAT_XRGB88888_A8: *1/ */
+/* /1* case COGL_PIXEL_FORMAT_XBGR88888_A8: *1/ */
+/* /1* case COGL_PIXEL_FORMAT_RGBX88888_A8: *1/ */
+/* /1* case COGL_PIXEL_FORMAT_BGRX88888_A8: *1/ */
+/* /1* case COGL_PIXEL_FORMAT_RGB888_A8: *1/ */
+/* /1* case COGL_PIXEL_FORMAT_BGR888_A8: *1/ */
+/* /1* case COGL_PIXEL_FORMAT_RGB565_A8: *1/ */
+/* /1* case COGL_PIXEL_FORMAT_BGR565_A8: *1/ */
+
+/* /1* /2* 3 planes *2/ *1/ */
+/* /1* case COGL_PIXEL_FORMAT_YUV410: *1/ */
+/* /1* case COGL_PIXEL_FORMAT_YVU410: *1/ */
+/* /1* case COGL_PIXEL_FORMAT_YUV411: *1/ */
+/* /1* case COGL_PIXEL_FORMAT_YVU411: *1/ */
+/* /1* case COGL_PIXEL_FORMAT_YUV420: *1/ */
+/* /1* case COGL_PIXEL_FORMAT_YVU420: *1/ */
+/* /1* case COGL_PIXEL_FORMAT_YUV422: *1/ */
+/* /1* case COGL_PIXEL_FORMAT_YVU422: *1/ */
+/* /1* case COGL_PIXEL_FORMAT_YUV444: *1/ */
+/* /1* case COGL_PIXEL_FORMAT_YVU444: *1/ */
+
+/* default: */
+/* /1* XXX At this point, we might crash 'n burn *1/ */
+/* g_assert_not_reached (); */
+/* components_out[0] = COGL_TEXTURE_COMPONENTS_RGB; */
+/* break; */
+/* } */
+/* } */
+/* else */
+/* { */
+/* if (format == COGL_PIXEL_FORMAT_ANY) */
+/* format = COGL_PIXEL_FORMAT_RGBA_8888_PRE; */
+
+/* if (format == COGL_PIXEL_FORMAT_A_8) */
+/* components_out[0] = COGL_TEXTURE_COMPONENTS_A; */
+/* else if (format == COGL_PIXEL_FORMAT_RG_88) */
+/* components_out[0] = COGL_TEXTURE_COMPONENTS_RG; */
+/* else if (format & COGL_DEPTH_BIT) */
+/* components_out[0] = COGL_TEXTURE_COMPONENTS_DEPTH; */
+/* else if (format & COGL_A_BIT) */
+/* components_out[0] = COGL_TEXTURE_COMPONENTS_RGBA; */
+/* else */
+/* components_out[0] = COGL_TEXTURE_COMPONENTS_RGB; */
+/* } */
+/* } */
diff --git a/cogl/cogl/cogl.h b/cogl/cogl/cogl.h
index 34a2408dc..0c31c7488 100644
--- a/cogl/cogl/cogl.h
+++ b/cogl/cogl/cogl.h
@@ -61,6 +61,7 @@
#include <cogl/cogl1-context.h>
#include <cogl/cogl-bitmap.h>
#include <cogl/cogl-color.h>
+#include <cogl/cogl-colorspace-conversion.h>
#include <cogl/cogl-matrix.h>
#include <cogl/cogl-matrix-stack.h>
#include <cogl/cogl-offscreen.h>
@@ -109,6 +110,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 2f9e3424c..fe4a53dfc 100644
--- a/cogl/cogl/driver/gl/cogl-texture-2d-gl.c
+++ b/cogl/cogl/driver/gl/cogl-texture-2d-gl.c
@@ -202,6 +202,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));
@@ -342,6 +344,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 fb36df2b8..6e065a147 100644
--- a/cogl/cogl/driver/gl/gl/cogl-driver-gl.c
+++ b/cogl/cogl/driver/gl/gl/cogl-driver-gl.c
@@ -267,6 +267,10 @@ _cogl_driver_pixel_format_to_gl (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 c2270124f..ddf443d14 100644
--- a/cogl/cogl/driver/gl/gl/cogl-texture-driver-gl.c
+++ b/cogl/cogl/driver/gl/gl/cogl-texture-driver-gl.c
@@ -98,6 +98,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 &&
@@ -203,6 +205,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);
@@ -307,6 +311,8 @@ _cogl_texture_driver_upload_to_gl (CoglContext *ctx,
gboolean 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 38ac9a10c..c50d27b87 100644
--- a/cogl/cogl/meson.build
+++ b/cogl/cogl/meson.build
@@ -88,6 +88,7 @@ cogl_headers = [
'cogl-pipeline.h',
'cogl-pipeline-state.h',
'cogl-pipeline-layer-state.h',
+ 'cogl-pixel-format-conversion.h',
'cogl-primitives.h',
'cogl-texture.h',
'cogl-texture-2d.h',
@@ -123,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',
@@ -248,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-colorspace-conversion.c',
+ 'cogl-feature-private.c',
+ 'cogl-feature-private.h',
'cogl-buffer-private.h',
'cogl-buffer.c',
'cogl-pixel-buffer-private.h',
@@ -317,6 +320,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 a86a2bff0..43be08127 100644
--- a/src/compositor/meta-shaped-texture-private.h
+++ b/src/compositor/meta-shaped-texture-private.h
@@ -32,7 +32,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 90a02210d..5bf92ee50 100644
--- a/src/compositor/meta-shaped-texture.c
+++ b/src/compositor/meta-shaped-texture.c
@@ -89,7 +89,7 @@ struct _MetaShapedTexture
MetaTextureTower *paint_tower;
- CoglTexture *texture;
+ CoglMultiPlaneTexture *texture;
CoglTexture *mask_texture;
CoglSnippet *snippet;
@@ -97,6 +97,8 @@ struct _MetaShapedTexture
CoglPipeline *masked_pipeline;
CoglPipeline *unblended_pipeline;
+ CoglPixelFormatConversion *pixel_format_conversion;
+
gboolean is_y_inverted;
/* The region containing only fully opaque pixels */
@@ -277,9 +279,11 @@ set_clip_region (MetaShapedTexture *stex,
static void
meta_shaped_texture_reset_pipelines (MetaShapedTexture *stex)
{
- g_clear_pointer (&stex->base_pipeline, cogl_object_unref);
- g_clear_pointer (&stex->masked_pipeline, cogl_object_unref);
- g_clear_pointer (&stex->unblended_pipeline, cogl_object_unref);
+ g_warning ("resetting pipelines!");
+
+ cogl_clear_object (&stex->base_pipeline);
+ cogl_clear_object (&stex->masked_pipeline);
+ cogl_clear_object (&stex->unblended_pipeline);
}
static void
@@ -297,7 +301,8 @@ meta_shaped_texture_dispose (GObject *object)
meta_texture_tower_free (stex->paint_tower);
stex->paint_tower = NULL;
- g_clear_pointer (&stex->texture, cogl_object_unref);
+ cogl_clear_object (&stex->pixel_format_conversion);
+ cogl_clear_object (&stex->texture);
g_clear_pointer (&stex->opaque_region, cairo_region_destroy);
meta_shaped_texture_set_mask_texture (stex, NULL);
@@ -306,7 +311,7 @@ meta_shaped_texture_dispose (GObject *object)
meta_shaped_texture_reset_pipelines (stex);
- g_clear_pointer (&stex->snippet, cogl_object_unref);
+ cogl_clear_object (&stex->snippet);
G_OBJECT_CLASS (meta_shaped_texture_parent_class)->dispose (object);
}
@@ -317,19 +322,20 @@ get_base_pipeline (MetaShapedTexture *stex,
{
CoglPipeline *pipeline;
CoglMatrix matrix;
+ guint i = 0;
if (stex->base_pipeline)
return stex->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 (stex->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);
+ }
cogl_matrix_init_identity (&matrix);
@@ -413,7 +419,10 @@ get_base_pipeline (MetaShapedTexture *stex,
cogl_pipeline_set_layer_matrix (pipeline, 1, &matrix);
if (stex->snippet)
- cogl_pipeline_add_layer_snippet (pipeline, 0, stex->snippet);
+ {
+ for (i = 0; i < cogl_multi_plane_texture_get_n_planes (stex->texture); i++)
+ cogl_pipeline_add_layer_snippet (pipeline, i, stex->snippet);
+ }
stex->base_pipeline = pipeline;
@@ -432,14 +441,19 @@ get_masked_pipeline (MetaShapedTexture *stex,
CoglContext *ctx)
{
CoglPipeline *pipeline;
+ gint i, n_layers = 0;
if (stex->masked_pipeline)
return stex->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);
+ }
stex->masked_pipeline = pipeline;
@@ -451,17 +465,15 @@ get_unblended_pipeline (MetaShapedTexture *stex,
CoglContext *ctx)
{
CoglPipeline *pipeline;
- CoglColor color;
if (stex->unblended_pipeline)
return stex->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);
stex->unblended_pipeline = pipeline;
@@ -503,23 +515,46 @@ paint_clipped_rectangle (MetaShapedTexture *stex,
}
static void
-set_cogl_texture (MetaShapedTexture *stex,
- CoglTexture *cogl_tex)
+check_texture_color_format (MetaShapedTexture *stex,
+ CoglMultiPlaneTexture *texture)
+{
+ CoglPixelFormat format = cogl_multi_plane_texture_get_format (texture);
+ guint n_layers = cogl_pipeline_get_n_layers (stex->base_pipeline);
+
+ if (stex->pixel_format_conversion != NULL)
+ return;
+
+ cogl_clear_object (&stex->pixel_format_conversion);
+ stex->pixel_format_conversion = cogl_pixel_format_conversion_new (format);
+
+ /* Check if a snippet is actually necessary */
+ if (stex->pixel_format_conversion == NULL)
+ return;
+
+ /* XXX disable for now, our changes are still incompatible with texturetower*/
+ meta_shaped_texture_set_create_mipmaps (stex, FALSE);
+
+ cogl_pixel_format_conversion_attach_to_pipeline (stex->pixel_format_conversion,
+ stex->base_pipeline,
+ n_layers - 1);
+}
+
+static void
+set_planar_texture (MetaShapedTexture *stex,
+ CoglMultiPlaneTexture *planar_tex)
{
int width, height;
g_return_if_fail (META_IS_SHAPED_TEXTURE (stex));
- if (stex->texture)
- cogl_object_unref (stex->texture);
-
- stex->texture = cogl_tex;
+ cogl_clear_object (&stex->texture);
+ stex->texture = planar_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
{
@@ -535,13 +570,24 @@ set_cogl_texture (MetaShapedTexture *stex,
update_size (stex);
}
+ /* Check if we need to do color conversion to RGBA */
+ if (planar_tex != NULL && stex->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 (stex->create_mipmaps)
- meta_texture_tower_set_base_texture (stex->paint_tower, cogl_tex);
+ if (FALSE)
+ /* if (stex->create_mipmaps) */
+ {
+ /* XXX */
+ CoglTexture *cogl_tex = cogl_multi_plane_texture_get_plane (planar_tex, 0);
+ meta_texture_tower_set_base_texture (stex->paint_tower, cogl_tex);
+ }
}
static gboolean
@@ -559,10 +605,10 @@ texture_is_idle_and_not_mipmapped (gpointer user_data)
}
static void
-do_paint (MetaShapedTexture *stex,
- CoglFramebuffer *fb,
- CoglTexture *paint_tex,
- cairo_region_t *clip_region)
+do_paint (MetaShapedTexture *stex,
+ CoglFramebuffer *fb,
+ CoglMultiPlaneTexture *paint_tex,
+ cairo_region_t *clip_region)
{
double tex_scale;
int dst_width, dst_height;
@@ -575,8 +621,12 @@ do_paint (MetaShapedTexture *stex,
CoglContext *ctx;
ClutterActorBox alloc;
CoglPipelineFilter filter;
+ guint n_planes;
clutter_actor_get_scale (CLUTTER_ACTOR (stex), &tex_scale, NULL);
+
+ n_planes = cogl_multi_plane_texture_get_n_planes (paint_tex);
+
ensure_size_valid (stex);
dst_width = stex->dst_width;
@@ -682,8 +732,15 @@ do_paint (MetaShapedTexture *stex,
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++)
@@ -714,6 +771,7 @@ do_paint (MetaShapedTexture *stex,
if (!blended_tex_region || !cairo_region_is_empty (blended_tex_region))
{
CoglPipeline *blended_pipeline;
+ guint i;
if (stex->mask_texture == NULL)
{
@@ -722,16 +780,21 @@ do_paint (MetaShapedTexture *stex,
else
{
blended_pipeline = get_masked_pipeline (stex, ctx);
- cogl_pipeline_set_layer_texture (blended_pipeline, 1, stex->mask_texture);
- cogl_pipeline_set_layer_filters (blended_pipeline, 1, filter, filter);
+ cogl_pipeline_set_layer_texture (blended_pipeline, n_planes, stex->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)
{
@@ -773,7 +836,7 @@ static void
meta_shaped_texture_paint (ClutterActor *actor)
{
MetaShapedTexture *stex = META_SHAPED_TEXTURE (actor);
- CoglTexture *paint_tex;
+ CoglMultiPlaneTexture *paint_tex;
CoglFramebuffer *fb;
if (!stex->texture)
@@ -800,39 +863,40 @@ 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 (stex->create_mipmaps)
+ /* if (stex->create_mipmaps) */
+ if (FALSE)
{
- int64_t now = g_get_monotonic_time ();
- int64_t age = now - stex->last_invalidation;
-
- if (age >= MIN_MIPMAP_AGE_USEC ||
- stex->fast_updates < MIN_FAST_UPDATES_BEFORE_UNMIPMAP)
- {
- paint_tex = meta_texture_tower_get_paint_texture (stex->paint_tower);
- if (!paint_tex)
- paint_tex = stex->texture;
- }
- else
- {
- paint_tex = stex->texture;
-
- /* Minus 1000 to ensure we don't fail the age test in timeout */
- stex->earliest_remipmap = now + MIN_MIPMAP_AGE_USEC - 1000;
-
- if (!stex->remipmap_timeout_id)
- stex->remipmap_timeout_id =
- g_timeout_add (MIN_MIPMAP_AGE_USEC / 1000,
- texture_is_idle_and_not_mipmapped,
- stex);
- }
+ /* int64_t now = g_get_monotonic_time (); */
+ /* int64_t age = now - stex->last_invalidation; */
+
+ /* if (age >= MIN_MIPMAP_AGE_USEC || */
+ /* stex->fast_updates < MIN_FAST_UPDATES_BEFORE_UNMIPMAP) */
+ /* { */
+ /* paint_tex = meta_texture_tower_get_paint_texture (stex->paint_tower); */
+ /* if (!paint_tex) */
+ /* paint_tex = stex->texture; */
+ /* } */
+ /* else */
+ /* { */
+ /* paint_tex = stex->texture; */
+
+ /* /1* Minus 1000 to ensure we don't fail the age test in timeout *1/ */
+ /* stex->earliest_remipmap = now + MIN_MIPMAP_AGE_USEC - 1000; */
+
+ /* if (!stex->remipmap_timeout_id) */
+ /* stex->remipmap_timeout_id = */
+ /* g_timeout_add (MIN_MIPMAP_AGE_USEC / 1000, */
+ /* texture_is_idle_and_not_mipmapped, */
+ /* stex); */
+ /* } */
}
else
{
- paint_tex = COGL_TEXTURE (stex->texture);
+ paint_tex = stex->texture;
}
- if (cogl_texture_get_width (paint_tex) == 0 ||
- cogl_texture_get_height (paint_tex) == 0)
+ if (cogl_multi_plane_texture_get_width (paint_tex) == 0 ||
+ cogl_multi_plane_texture_get_height (paint_tex) == 0)
return;
fb = cogl_get_draw_framebuffer ();
@@ -1089,15 +1153,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);
}
/**
@@ -1127,7 +1191,7 @@ meta_shaped_texture_set_snippet (MetaShapedTexture *stex,
meta_shaped_texture_reset_pipelines (stex);
- g_clear_pointer (&stex->snippet, cogl_object_unref);
+ cogl_clear_object (&stex->snippet);
if (snippet)
stex->snippet = cogl_object_ref (snippet);
}
@@ -1138,11 +1202,12 @@ meta_shaped_texture_set_snippet (MetaShapedTexture *stex,
*
* Returns: (transfer none): the unshaped texture
*/
-CoglTexture *
+CoglMultiPlaneTexture *
meta_shaped_texture_get_texture (MetaShapedTexture *stex)
{
g_return_val_if_fail (META_IS_SHAPED_TEXTURE (stex), NULL);
- return COGL_TEXTURE (stex->texture);
+
+ return stex->texture;
}
/**
@@ -1364,17 +1429,20 @@ get_image_via_offscreen (MetaShapedTexture *stex,
* Returns: (transfer full): a new cairo surface to be freed with
* cairo_surface_destroy().
*/
+ /* XXX Still need to fix this, but apparently only used for screenshot */
cairo_surface_t *
meta_shaped_texture_get_image (MetaShapedTexture *stex,
cairo_rectangle_int_t *clip)
{
cairo_rectangle_int_t *transformed_clip = NULL;
- CoglTexture *texture, *mask_texture;
+ CoglMultiPlaneTexture *texture;
+ CoglTexture *mask_texture;
cairo_surface_t *surface;
+ CoglContext *ctx;
g_return_val_if_fail (META_IS_SHAPED_TEXTURE (stex), NULL);
- texture = COGL_TEXTURE (stex->texture);
+ texture = stex->texture;
if (texture == NULL)
return NULL;
@@ -1417,9 +1485,10 @@ meta_shaped_texture_get_image (MetaShapedTexture *stex,
transformed_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));
@@ -1444,8 +1513,8 @@ meta_shaped_texture_get_image (MetaShapedTexture *stex,
transformed_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),
@@ -1518,5 +1587,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 244b1e885..446772d4b 100644
--- a/src/compositor/meta-surface-actor-x11.c
+++ b/src/compositor/meta-surface-actor-x11.c
@@ -45,7 +45,7 @@ struct _MetaSurfaceActorX11
MetaDisplay *display;
- CoglTexture *texture;
+ CoglMultiPlaneTexture *texture;
Pixmap pixmap;
Damage damage;
@@ -129,8 +129,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");
- self->texture = texture;
- meta_shaped_texture_set_texture (stex, texture);
+ /* FIXME: we need to find out the format here */
+ self->texture = cogl_multi_plane_texture_new_single_plane (COGL_PIXEL_FORMAT_ANY, texture);
+ meta_shaped_texture_set_texture (stex, self->texture);
}
static void
@@ -187,6 +188,7 @@ meta_surface_actor_x11_process_damage (MetaSurfaceActor *actor,
int x, int y, int width, int height)
{
MetaSurfaceActorX11 *self = META_SURFACE_ACTOR_X11 (actor);
+ CoglTexture *texture;
self->received_damage = TRUE;
@@ -210,7 +212,8 @@ meta_surface_actor_x11_process_damage (MetaSurfaceActor *actor,
if (!is_visible (self))
return;
- cogl_texture_pixmap_x11_update_area (COGL_TEXTURE_PIXMAP_X11 (self->texture),
+ texture = cogl_multi_plane_texture_get_plane (self->texture, 0);
+ cogl_texture_pixmap_x11_update_area (COGL_TEXTURE_PIXMAP_X11 (texture),
x, y, width, height);
}
diff --git a/src/compositor/meta-surface-actor.c b/src/compositor/meta-surface-actor.c
index ca4ca19a9..e50ca06f6 100644
--- a/src/compositor/meta-surface-actor.c
+++ b/src/compositor/meta-surface-actor.c
@@ -325,7 +325,8 @@ gboolean
meta_surface_actor_is_argb32 (MetaSurfaceActor *self)
{
MetaShapedTexture *stex = meta_surface_actor_get_texture (self);
- CoglTexture *texture = meta_shaped_texture_get_texture (stex);
+ CoglMultiPlaneTexture *mtex = meta_shaped_texture_get_texture (stex);
+ CoglTexture *texture;
/* If we don't have a texture, like during initialization, assume
* that we're ARGB32.
@@ -335,9 +336,14 @@ meta_surface_actor_is_argb32 (MetaSurfaceActor *self)
* place. This prevents us from continually redirecting and
* unredirecting on every paint.
*/
- if (!texture)
+ if (!mtex)
return !meta_surface_actor_is_unredirected (self);
+ /* Are we dealing with multiple planes? Then it can't be argb32 either */
+ if (cogl_multi_plane_texture_get_n_planes (mtex) != 1)
+ return FALSE;
+
+ texture = cogl_multi_plane_texture_get_plane (mtex, 0);
switch (cogl_texture_get_components (texture))
{
case COGL_TEXTURE_COMPONENTS_A:
diff --git a/src/meta/meta-shaped-texture.h b/src/meta/meta-shaped-texture.h
index c36b8547f..dd4548cb5 100644
--- a/src/meta/meta-shaped-texture.h
+++ b/src/meta/meta-shaped-texture.h
@@ -52,7 +52,7 @@ gboolean meta_shaped_texture_update_area (MetaShapedTexture *stex,
int height);
META_EXPORT
-CoglTexture * meta_shaped_texture_get_texture (MetaShapedTexture *stex);
+CoglMultiPlaneTexture * meta_shaped_texture_get_texture (MetaShapedTexture *stex);
META_EXPORT
void meta_shaped_texture_set_mask_texture (MetaShapedTexture *stex,
diff --git a/src/wayland/meta-wayland-buffer.c b/src/wayland/meta-wayland-buffer.c
index f45679d3a..32f6ae423 100644
--- a/src/wayland/meta-wayland-buffer.c
+++ b/src/wayland/meta-wayland-buffer.c
@@ -123,7 +123,7 @@ meta_wayland_buffer_realize (MetaWaylandBuffer *buffer)
stream = meta_wayland_egl_stream_new (buffer, NULL);
if (stream)
{
- CoglTexture2D *texture;
+ CoglMultiPlaneTexture *texture;
texture = meta_wayland_egl_stream_create_texture (stream, NULL);
if (!texture)
@@ -131,7 +131,7 @@ meta_wayland_buffer_realize (MetaWaylandBuffer *buffer)
buffer->egl_stream.stream = stream;
buffer->type = META_WAYLAND_BUFFER_TYPE_EGL_STREAM;
- buffer->egl_stream.texture = COGL_TEXTURE (texture);
+ buffer->egl_stream.texture = texture;
buffer->is_y_inverted = meta_wayland_egl_stream_is_y_inverted (stream);
return TRUE;
@@ -163,17 +163,18 @@ shm_buffer_get_cogl_pixel_format (struct wl_shm_buffer *shm_buffer,
CoglTextureComponents *components_out)
{
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
case WL_SHM_FORMAT_ARGB8888:
format = COGL_PIXEL_FORMAT_ARGB_8888_PRE;
+ components_out[0] = COGL_TEXTURE_COMPONENTS_RGBA;
break;
case WL_SHM_FORMAT_XRGB8888:
format = COGL_PIXEL_FORMAT_ARGB_8888;
- components = COGL_TEXTURE_COMPONENTS_RGB;
+ components_out[0] = COGL_TEXTURE_COMPONENTS_RGB;
break;
#elif G_BYTE_ORDER == G_LITTLE_ENDIAN
case WL_SHM_FORMAT_ARGB8888:
@@ -181,25 +182,59 @@ shm_buffer_get_cogl_pixel_format (struct wl_shm_buffer *shm_buffer,
break;
case WL_SHM_FORMAT_XRGB8888:
format = COGL_PIXEL_FORMAT_BGRA_8888;
- components = COGL_TEXTURE_COMPONENTS_RGB;
+ components_out[0] = COGL_TEXTURE_COMPONENTS_RGB;
break;
#endif
+ case WL_SHM_FORMAT_NV12:
+ format = COGL_PIXEL_FORMAT_NV12;
+ components_out[0] = COGL_TEXTURE_COMPONENTS_A;
+ components_out[1] = COGL_TEXTURE_COMPONENTS_RG;
+ break;
+ case WL_SHM_FORMAT_NV21:
+ format = COGL_PIXEL_FORMAT_NV21;
+ components_out[0] = COGL_TEXTURE_COMPONENTS_A;
+ components_out[1] = COGL_TEXTURE_COMPONENTS_RG;
+ break;
+ case WL_SHM_FORMAT_YUV422:
+ format = COGL_PIXEL_FORMAT_YUV422;
+ components_out[0] = COGL_TEXTURE_COMPONENTS_A;
+ components_out[1] = COGL_TEXTURE_COMPONENTS_A;
+ components_out[2] = COGL_TEXTURE_COMPONENTS_A;
+ break;
+ case WL_SHM_FORMAT_YVU422:
+ format = COGL_PIXEL_FORMAT_YVU422;
+ components_out[0] = COGL_TEXTURE_COMPONENTS_A;
+ components_out[1] = COGL_TEXTURE_COMPONENTS_A;
+ components_out[2] = COGL_TEXTURE_COMPONENTS_A;
+ break;
+ case WL_SHM_FORMAT_YUV444:
+ format = COGL_PIXEL_FORMAT_YUV444;
+ components_out[0] = COGL_TEXTURE_COMPONENTS_A;
+ components_out[1] = COGL_TEXTURE_COMPONENTS_A;
+ components_out[2] = COGL_TEXTURE_COMPONENTS_A;
+ break;
+ case WL_SHM_FORMAT_YVU444:
+ format = COGL_PIXEL_FORMAT_YVU444;
+ components_out[0] = COGL_TEXTURE_COMPONENTS_A;
+ components_out[1] = COGL_TEXTURE_COMPONENTS_A;
+ components_out[2] = COGL_TEXTURE_COMPONENTS_A;
+ break;
+
default:
g_warn_if_reached ();
format = COGL_PIXEL_FORMAT_ARGB_8888;
+ components_out[0] = COGL_TEXTURE_COMPONENTS_RGBA;
}
if (format_out)
*format_out = format;
- if (components_out)
- *components_out = components;
}
static gboolean
-shm_buffer_attach (MetaWaylandBuffer *buffer,
- CoglTexture **texture,
- gboolean *changed_texture,
- GError **error)
+shm_buffer_attach (MetaWaylandBuffer *buffer,
+ CoglMultiPlaneTexture **texture,
+ gboolean *changed_texture,
+ GError **error)
{
MetaBackend *backend = meta_get_backend ();
ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
@@ -207,21 +242,27 @@ shm_buffer_attach (MetaWaylandBuffer *buffer,
struct wl_shm_buffer *shm_buffer;
int stride, width, height;
CoglPixelFormat format;
- CoglTextureComponents components;
- CoglBitmap *bitmap;
- CoglTexture *new_texture;
-
+ CoglTextureComponents components[3];
+ guint i, n_planes;
+ guint h_factors[3], v_factors[3];
+ gsize offset = 0;
+ const guint8 *data;
+ GPtrArray *bitmaps;
+
+ /* 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);
- shm_buffer_get_cogl_pixel_format (shm_buffer, &format, &components);
+ 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);
if (*texture &&
- cogl_texture_get_width (*texture) == width &&
- cogl_texture_get_height (*texture) == height &&
- cogl_texture_get_components (*texture) == components &&
- _cogl_texture_get_format (*texture) == format)
+ cogl_multi_plane_texture_get_width (*texture) == width &&
+ cogl_multi_plane_texture_get_height (*texture) == height &&
+ /*XXX cogl_texture_get_components (*texture) == components && */
+ cogl_multi_plane_texture_get_format (*texture) == format)
{
buffer->is_y_inverted = TRUE;
*changed_texture = FALSE;
@@ -230,56 +271,57 @@ shm_buffer_attach (MetaWaylandBuffer *buffer,
cogl_clear_object (texture);
+ /* Safely access the data inside the buffer */
wl_shm_buffer_begin_access (shm_buffer);
+ data = wl_shm_buffer_get_data (shm_buffer);
- bitmap = cogl_bitmap_new_for_data (cogl_context,
- width, height,
- format,
- stride,
- wl_shm_buffer_get_data (shm_buffer));
-
- new_texture = COGL_TEXTURE (cogl_texture_2d_new_from_bitmap (bitmap));
- cogl_texture_set_components (new_texture, components);
-
- if (!cogl_texture_allocate (new_texture, error))
+ bitmaps = g_ptr_array_new_full (n_planes, cogl_object_unref);
+ for (i = 0; i < n_planes; i++)
{
- g_clear_pointer (&new_texture, cogl_object_unref);
- if (g_error_matches (*error, COGL_TEXTURE_ERROR, COGL_TEXTURE_ERROR_SIZE))
- {
- CoglTexture2DSliced *texture_sliced;
-
- g_clear_error (error);
-
- texture_sliced =
- cogl_texture_2d_sliced_new_from_bitmap (bitmap,
- COGL_TEXTURE_MAX_WASTE);
- new_texture = COGL_TEXTURE (texture_sliced);
- cogl_texture_set_components (new_texture, components);
-
- if (!cogl_texture_allocate (new_texture, error))
- g_clear_pointer (&new_texture, cogl_object_unref);
- }
+ CoglBitmap *bitmap;
+
+ /* 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]);
+
+ g_warning ("Creating plane %d, h_factor = %d, v_factor = %d, offset = %lu",
+ i, h_factors[i], v_factors[i], offset);
+
+ bitmap = cogl_bitmap_new_for_data (cogl_context,
+ width / h_factors[i],
+ height / v_factors[i],
+ format, /* XXX this we have to change later */
+ stride, /* XXX Do we need to change this too?*/
+ data + offset);
+ g_assert (bitmap);
+
+ g_ptr_array_add (bitmaps, bitmap);
}
- cogl_object_unref (bitmap);
+ *texture = cogl_multi_plane_texture_new_from_bitmaps (format,
+ g_ptr_array_free (bitmaps, FALSE),
+ n_planes, error);
wl_shm_buffer_end_access (shm_buffer);
- if (!new_texture)
- return FALSE;
-
- *texture = new_texture;
*changed_texture = TRUE;
buffer->is_y_inverted = TRUE;
+ g_warning ("Got the following multiplane texture:\n%s", cogl_multi_plane_texture_to_string (*texture));
+ /* g_ptr_array_free (bitmaps, TRUE); */
+
return TRUE;
}
static gboolean
-egl_image_buffer_attach (MetaWaylandBuffer *buffer,
- CoglTexture **texture,
- gboolean *changed_texture,
- GError **error)
+egl_image_buffer_attach (MetaWaylandBuffer *buffer,
+ CoglMultiPlaneTexture **texture,
+ gboolean *changed_texture,
+ GError **error)
{
MetaBackend *backend = meta_get_backend ();
MetaEgl *egl = meta_backend_get_egl (backend);
@@ -288,8 +330,8 @@ 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_2d;
+ guint i, n_planes;
+ GPtrArray *planes;
if (buffer->egl_image.texture)
{
@@ -299,6 +341,7 @@ egl_image_buffer_attach (MetaWaylandBuffer *buffer,
return TRUE;
}
+ /* Query the necessary properties */
if (!meta_egl_query_wayland_buffer (egl, egl_display, buffer->resource,
EGL_TEXTURE_FORMAT, &format,
error))
@@ -319,6 +362,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:
@@ -327,6 +371,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,
@@ -334,27 +386,49 @@ 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_2d = 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++)
+ {
+ EGLint egl_attribs[3];
+ EGLImageKHR egl_img;
+ CoglTexture2D *texture_2d;
- meta_egl_destroy_image (egl, egl_display, egl_image, NULL);
+ /* Specify that we want the i'th plane */
+ egl_attribs[0] = EGL_WAYLAND_PLANE_WL;
+ egl_attribs[1] = i;
+ egl_attribs[2] = EGL_NONE;
+
+ /* 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,
+ egl_attribs,
+ error);
+
+ if (G_UNLIKELY (egl_img == EGL_NO_IMAGE_KHR))
+ goto on_error;
+
+ texture_2d = cogl_egl_texture_2d_new_from_image (cogl_context,
+ width, height,
+ cogl_format,
+ egl_img,
+ error);
+
+ meta_egl_destroy_image (egl, egl_display, egl_img, NULL);
+
+ if (G_UNLIKELY (!texture_2d))
+ goto on_error;
+
+ g_ptr_array_add (planes, texture_2d);
+ }
- if (!texture_2d)
- return FALSE;
- buffer->egl_image.texture = COGL_TEXTURE (texture_2d);
+ buffer->egl_image.texture = cogl_multi_plane_texture_new (cogl_format,
+ g_ptr_array_free (planes, FALSE),
+ n_planes);
buffer->is_y_inverted = !!y_inverted;
cogl_clear_object (texture);
@@ -362,14 +436,19 @@ egl_image_buffer_attach (MetaWaylandBuffer *buffer,
*changed_texture = TRUE;
return TRUE;
+
+on_error:
+ g_ptr_array_free (planes, TRUE);
+
+ return FALSE;
}
#ifdef HAVE_WAYLAND_EGLSTREAM
static gboolean
-egl_stream_buffer_attach (MetaWaylandBuffer *buffer,
- CoglTexture **texture,
- gboolean *changed_texture,
- GError **error)
+egl_stream_buffer_attach (MetaWaylandBuffer *buffer,
+ CoglMultiPlaneTexture **texture,
+ gboolean *changed_texture,
+ GError **error)
{
MetaWaylandEglStream *stream = buffer->egl_stream.stream;
@@ -406,10 +485,10 @@ egl_stream_buffer_attach (MetaWaylandBuffer *buffer,
* meta_wayland_buffer_attach(), which also might free it, as described above.
*/
gboolean
-meta_wayland_buffer_attach (MetaWaylandBuffer *buffer,
- CoglTexture **texture,
- gboolean *changed_texture,
- GError **error)
+meta_wayland_buffer_attach (MetaWaylandBuffer *buffer,
+ CoglMultiPlaneTexture **texture,
+ gboolean *changed_texture,
+ GError **error)
{
g_return_val_if_fail (buffer->resource, FALSE);
@@ -425,14 +504,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, texture, changed_texture, error);
case META_WAYLAND_BUFFER_TYPE_EGL_IMAGE:
+ g_warning ("GOT EGL IMAGE BUFFER");
return egl_image_buffer_attach (buffer, texture, changed_texture, error);
#ifdef HAVE_WAYLAND_EGLSTREAM
case META_WAYLAND_BUFFER_TYPE_EGL_STREAM:
+ g_warning ("GOT EGL STREAM BUFFER");
return egl_stream_buffer_attach (buffer, texture, changed_texture, error);
#endif
case META_WAYLAND_BUFFER_TYPE_DMA_BUF:
+ g_warning ("GOT DMA BUF BUFFER");
return meta_wayland_dma_buf_buffer_attach (buffer,
texture,
changed_texture,
@@ -466,55 +549,84 @@ meta_wayland_buffer_is_y_inverted (MetaWaylandBuffer *buffer)
}
static gboolean
-process_shm_buffer_damage (MetaWaylandBuffer *buffer,
- CoglTexture *texture,
- cairo_region_t *region,
- GError **error)
+process_shm_buffer_damage (MetaWaylandBuffer *buffer,
+ CoglMultiPlaneTexture *texture,
+ cairo_region_t *region,
+ GError **error)
{
struct wl_shm_buffer *shm_buffer;
- int i, n_rectangles;
+ gint j, n_rectangles;
gboolean set_texture_failed = FALSE;
+ CoglPixelFormat format;
+ CoglTextureComponents components[3];
+ guint h_factors[3], v_factors[3], bpp[3];
+ guint offset = 0;
+ const uint8_t *data;
+ int32_t stride;
+ guint i, n_planes = cogl_multi_plane_texture_get_n_planes (texture);
n_rectangles = cairo_region_num_rectangles (region);
shm_buffer = wl_shm_buffer_get (buffer->resource);
+
+ /* Get the data */
wl_shm_buffer_begin_access (shm_buffer);
+ data = wl_shm_buffer_get_data (shm_buffer);
- for (i = 0; i < n_rectangles; i++)
+ /* Query the necessary properties */
+ stride = wl_shm_buffer_get_stride (shm_buffer);
+ shm_buffer_get_cogl_pixel_format (shm_buffer, &format, components);
+ cogl_pixel_format_get_subsampling_factors (format, h_factors, v_factors);
+ cogl_pixel_format_get_bits_per_pixel (format, bpp);
+
+ for (i = 0; i < n_planes; i++)
{
- const uint8_t *data = wl_shm_buffer_get_data (shm_buffer);
- int32_t stride = wl_shm_buffer_get_stride (shm_buffer);
- CoglPixelFormat format;
- int bpp;
- cairo_rectangle_int_t rect;
-
- shm_buffer_get_cogl_pixel_format (shm_buffer, &format, NULL);
- bpp = _cogl_pixel_format_get_bytes_per_pixel (format);
- cairo_region_get_rectangle (region, i, &rect);
-
- if (!_cogl_texture_set_region (texture,
- rect.width, rect.height,
- format,
- stride,
- data + rect.x * bpp + rect.y * stride,
- rect.x, rect.y,
- 0,
- error))
+ CoglTexture *plane;
+
+ plane = cogl_multi_plane_texture_get_plane (texture, i);
+
+ for (j = 0; j < n_rectangles; j++)
{
- set_texture_failed = TRUE;
- break;
+ cairo_rectangle_int_t rect;
+
+ cairo_region_get_rectangle (region, i, &rect);
+
+ /* It's possible we get a faulty rectangle of size zero: ignore */
+ if (rect.height == 0 || rect.width == 0)
+ continue;
+
+ /* Calculate the offset in the buffer */
+ if (i > 0)
+ offset += (stride / h_factors[i-1]) * (rect.height / v_factors[i-1]);
+
+ /* XXX don't we need the bpp here? */
+ if (!_cogl_texture_set_region (plane,
+ rect.width / h_factors[i],
+ rect.height / v_factors[i],
+ _cogl_texture_get_format (plane),
+ stride,
+ /* data + offset + rect.x * bpp + rect.y * stride, */
+ data + offset,
+ rect.x, rect.y,
+ 0,
+ error))
+ {
+ set_texture_failed = TRUE;
+ goto out;
+ }
}
}
+out:
wl_shm_buffer_end_access (shm_buffer);
return !set_texture_failed;
}
void
-meta_wayland_buffer_process_damage (MetaWaylandBuffer *buffer,
- CoglTexture *texture,
- cairo_region_t *region)
+meta_wayland_buffer_process_damage (MetaWaylandBuffer *buffer,
+ CoglMultiPlaneTexture *texture,
+ cairo_region_t *region)
{
gboolean res = FALSE;
GError *error = NULL;
diff --git a/src/wayland/meta-wayland-buffer.h b/src/wayland/meta-wayland-buffer.h
index 5d75a3451..07522f27b 100644
--- a/src/wayland/meta-wayland-buffer.h
+++ b/src/wayland/meta-wayland-buffer.h
@@ -56,19 +56,19 @@ struct _MetaWaylandBuffer
MetaWaylandBufferType type;
struct {
- CoglTexture *texture;
+ CoglMultiPlaneTexture *texture;
} egl_image;
#ifdef HAVE_WAYLAND_EGLSTREAM
struct {
MetaWaylandEglStream *stream;
- CoglTexture *texture;
+ CoglMultiPlaneTexture *texture;
} egl_stream;
#endif
struct {
MetaWaylandDmaBufBuffer *dma_buf;
- CoglTexture *texture;
+ CoglMultiPlaneTexture *texture;
} dma_buf;
};
@@ -80,14 +80,14 @@ MetaWaylandBuffer * meta_wayland_buffer_from_resource (struct wl_resou
struct wl_resource * meta_wayland_buffer_get_resource (MetaWaylandBuffer *buffer);
gboolean meta_wayland_buffer_is_realized (MetaWaylandBuffer *buffer);
gboolean meta_wayland_buffer_realize (MetaWaylandBuffer *buffer);
-gboolean meta_wayland_buffer_attach (MetaWaylandBuffer *buffer,
- CoglTexture **texture,
- gboolean *changed_texture,
- GError **error);
+gboolean meta_wayland_buffer_attach (MetaWaylandBuffer *buffer,
+ CoglMultiPlaneTexture **texture,
+ gboolean *changed_texture,
+ GError **error);
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,
- CoglTexture *texture,
+ CoglMultiPlaneTexture *texture,
cairo_region_t *region);
#endif /* META_WAYLAND_BUFFER_H */
diff --git a/src/wayland/meta-wayland-cursor-surface.c b/src/wayland/meta-wayland-cursor-surface.c
index d46b3511f..7ee2701e0 100644
--- a/src/wayland/meta-wayland-cursor-surface.c
+++ b/src/wayland/meta-wayland-cursor-surface.c
@@ -58,7 +58,7 @@ update_cursor_sprite_texture (MetaWaylandCursorSurface *cursor_surface)
MetaWaylandSurface *surface =
meta_wayland_surface_role_get_surface (META_WAYLAND_SURFACE_ROLE (cursor_surface));
MetaCursorSprite *cursor_sprite = META_CURSOR_SPRITE (priv->cursor_sprite);
- CoglTexture *texture;
+ CoglMultiPlaneTexture *texture;
if (!priv->cursor_renderer)
return;
@@ -66,8 +66,13 @@ update_cursor_sprite_texture (MetaWaylandCursorSurface *cursor_surface)
texture = meta_wayland_surface_get_texture (surface);
if (texture)
{
+ CoglTexture *plane;
+
+ /* XXX We assume that we get a simple (single-plane) texture here */
+ plane = cogl_multi_plane_texture_get_plane (texture, 0);
+
meta_cursor_sprite_set_texture (cursor_sprite,
- texture,
+ plane,
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 e49fba9cf..21efe2731 100644
--- a/src/wayland/meta-wayland-dma-buf.c
+++ b/src/wayland/meta-wayland-dma-buf.c
@@ -56,8 +56,10 @@ struct _MetaWaylandDmaBufBuffer
int width;
int height;
uint32_t drm_format;
- uint64_t drm_modifier;
bool is_y_inverted;
+
+ guint n_planes;
+ uint64_t drm_modifier[META_WAYLAND_DMA_BUF_MAX_FDS];
int fds[META_WAYLAND_DMA_BUF_MAX_FDS];
int offsets[META_WAYLAND_DMA_BUF_MAX_FDS];
unsigned int strides[META_WAYLAND_DMA_BUF_MAX_FDS];
@@ -65,6 +67,58 @@ struct _MetaWaylandDmaBufBuffer
G_DEFINE_TYPE (MetaWaylandDmaBufBuffer, meta_wayland_dma_buf_buffer, G_TYPE_OBJECT);
+static CoglPixelFormat
+drm_buffer_get_cogl_pixel_format (MetaWaylandDmaBufBuffer *dma_buf)
+{
+ g_warning ("Got dma format %d", dma_buf->drm_format);
+ switch (dma_buf->drm_format)
+ {
+ /*
+ * NOTE: The cogl_format here is only used for texture color channel
+ * swizzling as compared to COGL_PIXEL_FORMAT_ARGB. It is *not* used
+ * for accessing the buffer memory. EGL will access the buffer
+ * memory according to the DRM fourcc code. Cogl will not mmap
+ * and access the buffer memory at all.
+ */
+ case DRM_FORMAT_XRGB8888:
+ return COGL_PIXEL_FORMAT_RGB_888;
+ case DRM_FORMAT_ARGB8888:
+ return COGL_PIXEL_FORMAT_ARGB_8888_PRE;
+ case DRM_FORMAT_ARGB2101010:
+ return COGL_PIXEL_FORMAT_ARGB_2101010_PRE;
+ case DRM_FORMAT_RGB565:
+ return COGL_PIXEL_FORMAT_RGB_565;
+ case DRM_FORMAT_YUYV:
+ return COGL_PIXEL_FORMAT_YUYV;
+ case DRM_FORMAT_NV12:
+ return COGL_PIXEL_FORMAT_NV12;
+ case DRM_FORMAT_NV21:
+ return COGL_PIXEL_FORMAT_NV21;
+ case DRM_FORMAT_YUV410:
+ return COGL_PIXEL_FORMAT_YUV410;
+ case DRM_FORMAT_YVU410:
+ return COGL_PIXEL_FORMAT_YVU410;
+ case DRM_FORMAT_YUV411:
+ return COGL_PIXEL_FORMAT_YUV411;
+ case DRM_FORMAT_YVU411:
+ return COGL_PIXEL_FORMAT_YVU411;
+ case DRM_FORMAT_YUV420:
+ return COGL_PIXEL_FORMAT_YUV420;
+ case DRM_FORMAT_YVU420:
+ return COGL_PIXEL_FORMAT_YVU420;
+ case DRM_FORMAT_YUV422:
+ return COGL_PIXEL_FORMAT_YUV422;
+ case DRM_FORMAT_YVU422:
+ return COGL_PIXEL_FORMAT_YVU422;
+ case DRM_FORMAT_YUV444:
+ return COGL_PIXEL_FORMAT_YUV444;
+ case DRM_FORMAT_YVU444:
+ return COGL_PIXEL_FORMAT_YVU444;
+ default:
+ return COGL_PIXEL_FORMAT_ANY;
+ }
+}
+
static gboolean
meta_wayland_dma_buf_realize_texture (MetaWaylandBuffer *buffer,
GError **error)
@@ -76,42 +130,25 @@ meta_wayland_dma_buf_realize_texture (MetaWaylandBuffer *buffer,
EGLDisplay egl_display = cogl_egl_context_get_egl_display (cogl_context);
MetaWaylandDmaBufBuffer *dma_buf = buffer->dma_buf.dma_buf;
CoglPixelFormat cogl_format;
- EGLImageKHR egl_image;
- CoglTexture2D *texture;
EGLint attribs[64];
int attr_idx = 0;
+ GPtrArray *planes;
+ guint i = 0, n_planes = 1;
if (buffer->dma_buf.texture)
return TRUE;
- switch (dma_buf->drm_format)
+ cogl_format = drm_buffer_get_cogl_pixel_format (dma_buf);
+ if (G_UNLIKELY (cogl_format == COGL_PIXEL_FORMAT_ANY))
{
- /*
- * NOTE: The cogl_format here is only used for texture color channel
- * swizzling as compared to COGL_PIXEL_FORMAT_ARGB. It is *not* used
- * for accessing the buffer memory. EGL will access the buffer
- * memory according to the DRM fourcc code. Cogl will not mmap
- * and access the buffer memory at all.
- */
- case DRM_FORMAT_XRGB8888:
- cogl_format = COGL_PIXEL_FORMAT_RGB_888;
- break;
- case DRM_FORMAT_ARGB8888:
- cogl_format = COGL_PIXEL_FORMAT_ARGB_8888_PRE;
- break;
- case DRM_FORMAT_ARGB2101010:
- cogl_format = COGL_PIXEL_FORMAT_ARGB_2101010_PRE;
- break;
- case DRM_FORMAT_RGB565:
- cogl_format = COGL_PIXEL_FORMAT_RGB_565;
- break;
- default:
g_set_error (error, G_IO_ERROR,
G_IO_ERROR_FAILED,
"Unsupported buffer format %d", dma_buf->drm_format);
return FALSE;
}
+ g_warning ("Got cOGL format %d", cogl_format);
+ /* Can't we put the following inside the for loop? */
attribs[attr_idx++] = EGL_WIDTH;
attribs[attr_idx++] = dma_buf->width;
attribs[attr_idx++] = EGL_HEIGHT;
@@ -126,9 +163,9 @@ meta_wayland_dma_buf_realize_texture (MetaWaylandBuffer *buffer,
attribs[attr_idx++] = EGL_DMA_BUF_PLANE0_PITCH_EXT;
attribs[attr_idx++] = dma_buf->strides[0];
attribs[attr_idx++] = EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT;
- attribs[attr_idx++] = dma_buf->drm_modifier & 0xffffffff;
+ attribs[attr_idx++] = dma_buf->drm_modifier[0] & 0xffffffff;
attribs[attr_idx++] = EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT;
- attribs[attr_idx++] = dma_buf->drm_modifier >> 32;
+ attribs[attr_idx++] = dma_buf->drm_modifier[0] >> 32;
if (dma_buf->fds[1] >= 0)
{
@@ -139,9 +176,9 @@ meta_wayland_dma_buf_realize_texture (MetaWaylandBuffer *buffer,
attribs[attr_idx++] = EGL_DMA_BUF_PLANE1_PITCH_EXT;
attribs[attr_idx++] = dma_buf->strides[1];
attribs[attr_idx++] = EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT;
- attribs[attr_idx++] = dma_buf->drm_modifier & 0xffffffff;
+ attribs[attr_idx++] = dma_buf->drm_modifier[1] & 0xffffffff;
attribs[attr_idx++] = EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT;
- attribs[attr_idx++] = dma_buf->drm_modifier >> 32;
+ attribs[attr_idx++] = dma_buf->drm_modifier[1] >> 32;
}
if (dma_buf->fds[2] >= 0)
@@ -153,9 +190,9 @@ meta_wayland_dma_buf_realize_texture (MetaWaylandBuffer *buffer,
attribs[attr_idx++] = EGL_DMA_BUF_PLANE2_PITCH_EXT;
attribs[attr_idx++] = dma_buf->strides[2];
attribs[attr_idx++] = EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT;
- attribs[attr_idx++] = dma_buf->drm_modifier & 0xffffffff;
+ attribs[attr_idx++] = dma_buf->drm_modifier[2] & 0xffffffff;
attribs[attr_idx++] = EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT;
- attribs[attr_idx++] = dma_buf->drm_modifier >> 32;
+ attribs[attr_idx++] = dma_buf->drm_modifier[2] >> 32;
}
if (dma_buf->fds[3] >= 0)
@@ -167,46 +204,86 @@ meta_wayland_dma_buf_realize_texture (MetaWaylandBuffer *buffer,
attribs[attr_idx++] = EGL_DMA_BUF_PLANE3_PITCH_EXT;
attribs[attr_idx++] = dma_buf->strides[3];
attribs[attr_idx++] = EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT;
- attribs[attr_idx++] = dma_buf->drm_modifier & 0xffffffff;
+ attribs[attr_idx++] = dma_buf->drm_modifier[3] & 0xffffffff;
attribs[attr_idx++] = EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT;
- attribs[attr_idx++] = dma_buf->drm_modifier >> 32;
+ attribs[attr_idx++] = dma_buf->drm_modifier[3] >> 32;
}
attribs[attr_idx++] = EGL_NONE;
- attribs[attr_idx++] = EGL_NONE;
- /* The EXT_image_dma_buf_import spec states that EGL_NO_CONTEXT is to be used
- * in conjunction with the EGL_LINUX_DMA_BUF_EXT target. Similarly, the
- * native buffer is named in the attribs. */
- egl_image = meta_egl_create_image (egl, egl_display, EGL_NO_CONTEXT,
- EGL_LINUX_DMA_BUF_EXT, NULL, attribs,
- error);
- if (egl_image == EGL_NO_IMAGE_KHR)
- return FALSE;
+ n_planes = cogl_pixel_format_get_n_planes (cogl_format);
+ /* If this isn't correct, then something went very wrong, so bail out */
+ g_warning ("n_planes == %d <-> dma_buf planes = %d", n_planes, dma_buf->n_planes);
+ /* FIXME uncomment */
+ /* g_return_val_if_fail (n_planes == dma_buf->n_planes, FALSE); */
- texture = cogl_egl_texture_2d_new_from_image (cogl_context,
- dma_buf->width,
- dma_buf->height,
- cogl_format,
- egl_image,
- error);
+ /*XXX probeersel*/
+ /* cogl_format = COGL_PIXEL_FORMAT_NV12; */
- meta_egl_destroy_image (egl, egl_display, egl_image, NULL);
+ planes = g_ptr_array_new_full (n_planes, cogl_object_unref);
- if (!texture)
- return FALSE;
+ /* Each EGLImage is a plane in the final CoglMultiPlaneTexture */
+ for (i = 0; i < dma_buf->n_planes; i++)
+ {
+ EGLImageKHR egl_img;
+ CoglTexture2D *plane;
+
+ /* XXX can't we do this? */
+ /* if (dma_buf->fds[i] >= 0) */
+ /* { */
+ /* attribs[attr_idx++] = EGL_DMA_BUF_PLANE1_FD_EXT; */
+ /* attribs[attr_idx++] = dma_buf->fds[i]; */
+ /* attribs[attr_idx++] = EGL_DMA_BUF_PLANE1_OFFSET_EXT; */
+ /* attribs[attr_idx++] = dma_buf->offsets[i]; */
+ /* attribs[attr_idx++] = EGL_DMA_BUF_PLANE1_PITCH_EXT; */
+ /* attribs[attr_idx++] = dma_buf->strides[i]; */
+ /* attribs[attr_idx++] = EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT; */
+ /* attribs[attr_idx++] = dma_buf->drm_modifier[i] & 0xffffffff; */
+ /* attribs[attr_idx++] = EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT; */
+ /* attribs[attr_idx++] = dma_buf->drm_modifier[i] >> 32; */
+ /* } */
+
+ /* The EXT_image_dma_buf_import spec states that EGL_NO_CONTEXT is to be
+ * used in conjunction with the EGL_LINUX_DMA_BUF_EXT target. Similarly,
+ * the native buffer is named in the attribs. */
+ egl_img = meta_egl_create_image (egl, egl_display, EGL_NO_CONTEXT,
+ EGL_LINUX_DMA_BUF_EXT, NULL, attribs,
+ error);
+ if (G_UNLIKELY (egl_img == EGL_NO_IMAGE_KHR))
+ goto on_error;
+
+ plane = cogl_egl_texture_2d_new_from_image (cogl_context,
+ dma_buf->width,
+ dma_buf->height,
+ cogl_format,
+ egl_img,
+ error);
+
+ meta_egl_destroy_image (egl, egl_display, egl_img, NULL);
+
+ if (G_UNLIKELY (!plane))
+ goto on_error;
+
+ g_ptr_array_add (planes, plane);
+ }
- buffer->dma_buf.texture = COGL_TEXTURE (texture);
+ buffer->dma_buf.texture = cogl_multi_plane_texture_new (cogl_format,
+ g_ptr_array_free (planes, FALSE),
+ dma_buf->n_planes);
buffer->is_y_inverted = dma_buf->is_y_inverted;
return TRUE;
+
+on_error:
+ g_ptr_array_free (planes, TRUE);
+ return FALSE;
}
gboolean
-meta_wayland_dma_buf_buffer_attach (MetaWaylandBuffer *buffer,
- CoglTexture **texture,
- gboolean *changed_texture,
- GError **error)
+meta_wayland_dma_buf_buffer_attach (MetaWaylandBuffer *buffer,
+ CoglMultiPlaneTexture **texture,
+ gboolean *changed_texture,
+ GError **error)
{
if (!meta_wayland_dma_buf_realize_texture (buffer, error))
return FALSE;
@@ -233,8 +310,10 @@ buffer_params_add (struct wl_client *client,
drm_modifier = ((uint64_t) drm_modifier_hi) << 32;
drm_modifier |= ((uint64_t) drm_modifier_lo) & 0xffffffff;
+ g_warning ("buffer_params_add %d", plane_idx);
+
dma_buf = wl_resource_get_user_data (resource);
- if (!dma_buf)
+ if (G_UNLIKELY (!dma_buf))
{
wl_resource_post_error (resource,
ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_ALREADY_USED,
@@ -242,7 +321,7 @@ buffer_params_add (struct wl_client *client,
return;
}
- if (plane_idx >= META_WAYLAND_DMA_BUF_MAX_FDS)
+ if (G_UNLIKELY (plane_idx >= META_WAYLAND_DMA_BUF_MAX_FDS))
{
wl_resource_post_error (resource,
ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_PLANE_IDX,
@@ -251,7 +330,7 @@ buffer_params_add (struct wl_client *client,
return;
}
- if (dma_buf->fds[plane_idx] != -1)
+ if (G_UNLIKELY (dma_buf->fds[plane_idx] != -1))
{
wl_resource_post_error (resource,
ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_PLANE_SET,
@@ -260,17 +339,19 @@ buffer_params_add (struct wl_client *client,
return;
}
- if (dma_buf->drm_modifier != DRM_FORMAT_MOD_INVALID &&
- dma_buf->drm_modifier != drm_modifier)
- {
- wl_resource_post_error (resource,
- ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_WL_BUFFER,
- "mismatching modifier between planes");
- return;
- }
+ /* if (G_UNLIKELY (dma_buf->drm_modifier[plane_idx] != DRM_FORMAT_MOD_INVALID && */
+ /* dma_buf->drm_modifier != drm_modifier)) */
+ /* { */
+ /* wl_resource_post_error (resource, */
+ /* ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_WL_BUFFER, */
+ /* "mismatching modifier between planes"); */
+ /* return; */
+ /* } */
- dma_buf->drm_modifier = drm_modifier;
+
+ dma_buf->n_planes = plane_idx + 1;
dma_buf->fds[plane_idx] = fd;
+ dma_buf->drm_modifier[plane_idx] = drm_modifier;
dma_buf->offsets[plane_idx] = offset;
dma_buf->strides[plane_idx] = stride;
}
@@ -550,6 +631,16 @@ dma_buf_bind (struct wl_client *client,
send_modifiers (resource, DRM_FORMAT_XRGB8888);
send_modifiers (resource, DRM_FORMAT_ARGB2101010);
send_modifiers (resource, DRM_FORMAT_RGB565);
+ send_modifiers (resource, DRM_FORMAT_NV12);
+ send_modifiers (resource, DRM_FORMAT_YUV410);
+ send_modifiers (resource, DRM_FORMAT_YVU410);
+ send_modifiers (resource, DRM_FORMAT_YUV411);
+ send_modifiers (resource, DRM_FORMAT_YVU420);
+ send_modifiers (resource, DRM_FORMAT_YVU420);
+ send_modifiers (resource, DRM_FORMAT_YUV422);
+ send_modifiers (resource, DRM_FORMAT_YVU422);
+ send_modifiers (resource, DRM_FORMAT_YUV444);
+ send_modifiers (resource, DRM_FORMAT_YVU444);
}
gboolean
@@ -598,10 +689,12 @@ meta_wayland_dma_buf_buffer_init (MetaWaylandDmaBufBuffer *dma_buf)
{
int i;
- dma_buf->drm_modifier = DRM_FORMAT_MOD_INVALID;
for (i = 0; i < META_WAYLAND_DMA_BUF_MAX_FDS; i++)
- dma_buf->fds[i] = -1;
+ {
+ dma_buf->drm_modifier[i] = DRM_FORMAT_MOD_INVALID;
+ dma_buf->fds[i] = -1;
+ }
}
static void
diff --git a/src/wayland/meta-wayland-dma-buf.h b/src/wayland/meta-wayland-dma-buf.h
index 580a3e777..a2b4fd937 100644
--- a/src/wayland/meta-wayland-dma-buf.h
+++ b/src/wayland/meta-wayland-dma-buf.h
@@ -42,10 +42,10 @@ typedef struct _MetaWaylandDmaBufBuffer MetaWaylandDmaBufBuffer;
gboolean meta_wayland_dma_buf_init (MetaWaylandCompositor *compositor);
gboolean
-meta_wayland_dma_buf_buffer_attach (MetaWaylandBuffer *buffer,
- CoglTexture **texture,
- gboolean *changed_texture,
- GError **error);
+meta_wayland_dma_buf_buffer_attach (MetaWaylandBuffer *buffer,
+ CoglMultiPlaneTexture **texture,
+ gboolean *changed_texture,
+ GError **error);
MetaWaylandDmaBufBuffer *
meta_wayland_dma_buf_from_buffer (MetaWaylandBuffer *buffer);
diff --git a/src/wayland/meta-wayland-egl-stream.c b/src/wayland/meta-wayland-egl-stream.c
index 3f8908e67..33fd96311 100644
--- a/src/wayland/meta-wayland-egl-stream.c
+++ b/src/wayland/meta-wayland-egl-stream.c
@@ -132,7 +132,7 @@ struct _MetaWaylandEglStream
EGLStreamKHR egl_stream;
MetaWaylandBuffer *buffer;
- CoglTexture2D *texture;
+ CoglMultiPlaneTexture *texture;
gboolean is_y_inverted;
};
@@ -183,7 +183,7 @@ stream_texture_destroyed (gpointer data)
}
static gboolean
-alloc_egl_stream_texture (CoglTexture2D *texture,
+alloc_egl_stream_texture (CoglTexture2D *texture_2d,
gpointer user_data,
GError **error)
{
@@ -199,7 +199,7 @@ alloc_egl_stream_texture (CoglTexture2D *texture,
error);
}
-CoglTexture2D *
+CoglMultiPlaneTexture *
meta_wayland_egl_stream_create_texture (MetaWaylandEglStream *stream,
GError **error)
{
@@ -208,7 +208,7 @@ meta_wayland_egl_stream_create_texture (MetaWaylandEglStream *stream,
ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
CoglContext *cogl_context = clutter_backend_get_cogl_context (clutter_backend);
EGLDisplay egl_display = cogl_egl_context_get_egl_display (cogl_context);
- CoglTexture2D *texture;
+ CoglTexture2D *texture_2d;
int width, height;
int y_inverted;
@@ -230,29 +230,29 @@ meta_wayland_egl_stream_create_texture (MetaWaylandEglStream *stream,
NULL))
y_inverted = EGL_TRUE;
- texture =
+ texture_2d =
cogl_texture_2d_new_from_egl_image_external (cogl_context,
width, height,
alloc_egl_stream_texture,
g_object_ref (stream),
stream_texture_destroyed,
error);
- if (!texture)
+ if (!texture_2d)
{
g_object_unref (stream);
return NULL;
}
- if (!cogl_texture_allocate (COGL_TEXTURE (texture), error))
+ if (!cogl_texture_allocate (COGL_TEXTURE (texture_2d), error))
{
- cogl_object_unref (texture);
+ cogl_object_unref (texture_2d);
return NULL;
}
- stream->texture = texture;
+ stream->texture = cogl_multi_plane_texture_new_single_plane (format, texture_2d);
stream->is_y_inverted = !!y_inverted;
- return texture;
+ return stream->texture;
}
gboolean
diff --git a/src/wayland/meta-wayland-egl-stream.h b/src/wayland/meta-wayland-egl-stream.h
index fe488ed54..d548d9a72 100644
--- a/src/wayland/meta-wayland-egl-stream.h
+++ b/src/wayland/meta-wayland-egl-stream.h
@@ -45,8 +45,8 @@ MetaWaylandEglStream * meta_wayland_egl_stream_new (MetaWaylandBuffer *buffer,
gboolean meta_wayland_egl_stream_attach (MetaWaylandEglStream *stream,
GError **error);
-CoglTexture2D * meta_wayland_egl_stream_create_texture (MetaWaylandEglStream *stream,
- GError **error);
+CoglMultiPlaneTexture * meta_wayland_egl_stream_create_texture (MetaWaylandEglStream *stream,
+ GError **error);
CoglSnippet * meta_wayland_egl_stream_create_snippet (void);
gboolean meta_wayland_egl_stream_is_y_inverted (MetaWaylandEglStream *stream);
diff --git a/src/wayland/meta-wayland-shell-surface.c b/src/wayland/meta-wayland-shell-surface.c
index 04f2aaeea..41c8da710 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_surface_get_texture (surface);
- 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 da0acfcbb..afd7275b9 100644
--- a/src/wayland/meta-wayland-surface.c
+++ b/src/wayland/meta-wayland-surface.c
@@ -247,7 +247,7 @@ get_buffer_width (MetaWaylandSurface *surface)
MetaWaylandBuffer *buffer = meta_wayland_surface_get_buffer (surface);
if (buffer)
- return cogl_texture_get_width (surface->texture);
+ return cogl_multi_plane_texture_get_width (surface->texture);
else
return 0;
}
@@ -258,7 +258,7 @@ get_buffer_height (MetaWaylandSurface *surface)
MetaWaylandBuffer *buffer = meta_wayland_surface_get_buffer (surface);
if (buffer)
- return cogl_texture_get_height (surface->texture);
+ return cogl_multi_plane_texture_get_height (surface->texture);
else
return 0;
}
@@ -722,7 +722,7 @@ meta_wayland_surface_apply_pending_state (MetaWaylandSurface *surface,
if (changed_texture && meta_wayland_surface_get_actor (surface))
{
MetaShapedTexture *stex;
- CoglTexture *texture;
+ CoglMultiPlaneTexture *texture;
CoglSnippet *snippet;
gboolean is_y_inverted;
@@ -1843,7 +1843,7 @@ meta_wayland_surface_is_shortcuts_inhibited (MetaWaylandSurface *surface,
return g_hash_table_contains (surface->shortcut_inhibited_seats, seat);
}
-CoglTexture *
+CoglMultiPlaneTexture *
meta_wayland_surface_get_texture (MetaWaylandSurface *surface)
{
return surface->texture;
diff --git a/src/wayland/meta-wayland-surface.h b/src/wayland/meta-wayland-surface.h
index e244a3fdf..b82cdc600 100644
--- a/src/wayland/meta-wayland-surface.h
+++ b/src/wayland/meta-wayland-surface.h
@@ -149,7 +149,7 @@ struct _MetaWaylandSurface
GHashTable *outputs_to_destroy_notify_id;
MetaMonitorTransform buffer_transform;
- CoglTexture *texture;
+ CoglMultiPlaneTexture *texture;
/* Buffer reference state. */
struct {
@@ -319,7 +319,7 @@ void meta_wayland_surface_restore_shortcuts (MetaWaylandSurface *
gboolean meta_wayland_surface_is_shortcuts_inhibited (MetaWaylandSurface *surface,
MetaWaylandSeat *seat);
-CoglTexture * meta_wayland_surface_get_texture (MetaWaylandSurface *surface);
+CoglMultiPlaneTexture * meta_wayland_surface_get_texture (MetaWaylandSurface *surface);
MetaSurfaceActor * meta_wayland_surface_get_actor (MetaWaylandSurface *surface);
diff --git a/src/wayland/meta-wayland.c b/src/wayland/meta-wayland.c
index a593f0a7b..2f1ecf12f 100644
--- a/src/wayland/meta-wayland.c
+++ b/src/wayland/meta-wayland.c
@@ -306,6 +306,28 @@ meta_wayland_log_func (const char *fmt,
g_free (str);
}
+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,
+ WL_SHM_FORMAT_NV21,
+ WL_SHM_FORMAT_YUV422,
+ WL_SHM_FORMAT_YVU422,
+ WL_SHM_FORMAT_YUV444,
+ WL_SHM_FORMAT_YVU444
+ };
+
+ for (i = 0; i < G_N_ELEMENTS (SUPPORTED_FORMATS); i++)
+ {
+ wl_display_add_shm_format (display, SUPPORTED_FORMATS[i]);
+ }
+}
+
static void
meta_wayland_compositor_init (MetaWaylandCompositor *compositor)
{
@@ -318,6 +340,8 @@ meta_wayland_compositor_init (MetaWaylandCompositor *compositor)
compositor->wayland_display = wl_display_create ();
if (compositor->wayland_display == NULL)
g_error ("Failed to create the global wl_display");
+
+ add_supported_shm_formats (compositor->wayland_display);
}
static void
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]