diff --git a/cogl/cogl/cogl-bitmap-conversion.c b/cogl/cogl/cogl-bitmap-conversion.c index 73cf3153e..8feaf6594 100644 --- a/cogl/cogl/cogl-bitmap-conversion.c +++ b/cogl/cogl/cogl-bitmap-conversion.c @@ -320,7 +320,37 @@ _cogl_bitmap_needs_short_temp_buffer (CoglPixelFormat format) case COGL_PIXEL_FORMAT_DEPTH_32: case COGL_PIXEL_FORMAT_DEPTH_24_STENCIL_8: case COGL_PIXEL_FORMAT_ANY: + /* No support for YUV or multi-plane formats */ case COGL_PIXEL_FORMAT_YUV: + case COGL_PIXEL_FORMAT_YUYV: + case COGL_PIXEL_FORMAT_YVYU: + case COGL_PIXEL_FORMAT_UYVY: + case COGL_PIXEL_FORMAT_VYUY: + case COGL_PIXEL_FORMAT_AYUV: + case COGL_PIXEL_FORMAT_XRGB88888_A8: + case COGL_PIXEL_FORMAT_XBGR88888_A8: + case COGL_PIXEL_FORMAT_RGBX88888_A8: + case COGL_PIXEL_FORMAT_BGRX88888_A8: + case COGL_PIXEL_FORMAT_RGB888_A8: + case COGL_PIXEL_FORMAT_BGR888_A8: + case COGL_PIXEL_FORMAT_RGB565_A8: + case COGL_PIXEL_FORMAT_BGR565_A8: + case COGL_PIXEL_FORMAT_NV12: + case COGL_PIXEL_FORMAT_NV21: + case COGL_PIXEL_FORMAT_NV16: + case COGL_PIXEL_FORMAT_NV61: + case COGL_PIXEL_FORMAT_NV24: + case COGL_PIXEL_FORMAT_NV42: + case COGL_PIXEL_FORMAT_YUV410: + case COGL_PIXEL_FORMAT_YVU410: + case COGL_PIXEL_FORMAT_YUV411: + case COGL_PIXEL_FORMAT_YVU411: + case COGL_PIXEL_FORMAT_YUV420: + case COGL_PIXEL_FORMAT_YVU420: + case COGL_PIXEL_FORMAT_YUV422: + case COGL_PIXEL_FORMAT_YVU422: + case COGL_PIXEL_FORMAT_YUV444: + case COGL_PIXEL_FORMAT_YVU444: g_assert_not_reached (); case COGL_PIXEL_FORMAT_A_8: diff --git a/cogl/cogl/cogl-bitmap-packing.h b/cogl/cogl/cogl-bitmap-packing.h index 1b8e140ff..1a1196fd8 100644 --- a/cogl/cogl/cogl-bitmap-packing.h +++ b/cogl/cogl/cogl-bitmap-packing.h @@ -400,7 +400,37 @@ G_PASTE (_cogl_unpack_, component_size) (CoglPixelFormat format, case COGL_PIXEL_FORMAT_DEPTH_32: case COGL_PIXEL_FORMAT_DEPTH_24_STENCIL_8: case COGL_PIXEL_FORMAT_ANY: + /* No support for YUV or multi-plane formats */ case COGL_PIXEL_FORMAT_YUV: + case COGL_PIXEL_FORMAT_YUYV: + case COGL_PIXEL_FORMAT_YVYU: + case COGL_PIXEL_FORMAT_UYVY: + case COGL_PIXEL_FORMAT_VYUY: + case COGL_PIXEL_FORMAT_AYUV: + case COGL_PIXEL_FORMAT_XRGB88888_A8: + case COGL_PIXEL_FORMAT_XBGR88888_A8: + case COGL_PIXEL_FORMAT_RGBX88888_A8: + case COGL_PIXEL_FORMAT_BGRX88888_A8: + case COGL_PIXEL_FORMAT_RGB888_A8: + case COGL_PIXEL_FORMAT_BGR888_A8: + case COGL_PIXEL_FORMAT_RGB565_A8: + case COGL_PIXEL_FORMAT_BGR565_A8: + case COGL_PIXEL_FORMAT_NV12: + case COGL_PIXEL_FORMAT_NV21: + case COGL_PIXEL_FORMAT_NV16: + case COGL_PIXEL_FORMAT_NV61: + case COGL_PIXEL_FORMAT_NV24: + case COGL_PIXEL_FORMAT_NV42: + case COGL_PIXEL_FORMAT_YUV410: + case COGL_PIXEL_FORMAT_YVU410: + case COGL_PIXEL_FORMAT_YUV411: + case COGL_PIXEL_FORMAT_YVU411: + case COGL_PIXEL_FORMAT_YUV420: + case COGL_PIXEL_FORMAT_YVU420: + case COGL_PIXEL_FORMAT_YUV422: + case COGL_PIXEL_FORMAT_YVU422: + case COGL_PIXEL_FORMAT_YUV444: + case COGL_PIXEL_FORMAT_YVU444: g_assert_not_reached (); } } @@ -761,7 +791,37 @@ G_PASTE (_cogl_pack_, component_size) (CoglPixelFormat format, case COGL_PIXEL_FORMAT_DEPTH_32: case COGL_PIXEL_FORMAT_DEPTH_24_STENCIL_8: case COGL_PIXEL_FORMAT_ANY: + /* No support for YUV or multi-plane formats */ case COGL_PIXEL_FORMAT_YUV: + case COGL_PIXEL_FORMAT_YUYV: + case COGL_PIXEL_FORMAT_YVYU: + case COGL_PIXEL_FORMAT_UYVY: + case COGL_PIXEL_FORMAT_VYUY: + case COGL_PIXEL_FORMAT_AYUV: + case COGL_PIXEL_FORMAT_XRGB88888_A8: + case COGL_PIXEL_FORMAT_XBGR88888_A8: + case COGL_PIXEL_FORMAT_RGBX88888_A8: + case COGL_PIXEL_FORMAT_BGRX88888_A8: + case COGL_PIXEL_FORMAT_RGB888_A8: + case COGL_PIXEL_FORMAT_BGR888_A8: + case COGL_PIXEL_FORMAT_RGB565_A8: + case COGL_PIXEL_FORMAT_BGR565_A8: + case COGL_PIXEL_FORMAT_NV12: + case COGL_PIXEL_FORMAT_NV21: + case COGL_PIXEL_FORMAT_NV16: + case COGL_PIXEL_FORMAT_NV61: + case COGL_PIXEL_FORMAT_NV24: + case COGL_PIXEL_FORMAT_NV42: + case COGL_PIXEL_FORMAT_YUV410: + case COGL_PIXEL_FORMAT_YVU410: + case COGL_PIXEL_FORMAT_YUV411: + case COGL_PIXEL_FORMAT_YVU411: + case COGL_PIXEL_FORMAT_YUV420: + case COGL_PIXEL_FORMAT_YVU420: + case COGL_PIXEL_FORMAT_YUV422: + case COGL_PIXEL_FORMAT_YVU422: + case COGL_PIXEL_FORMAT_YUV444: + case COGL_PIXEL_FORMAT_YVU444: g_assert_not_reached (); } } diff --git a/cogl/cogl/cogl-multi-plane-texture.c b/cogl/cogl/cogl-multi-plane-texture.c new file mode 100644 index 000000000..d8ea95373 --- /dev/null +++ b/cogl/cogl/cogl-multi-plane-texture.c @@ -0,0 +1,252 @@ +/* + * Authored By Niels De Graef + * + * 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 . + */ + +#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 = %s;\n", cogl_pixel_format_to_string (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 = %s },\n", + plane, + cogl_pixel_format_to_string (_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 + * + * 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 + * #CoglTextures 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..6b505705e --- /dev/null +++ b/cogl/cogl/cogl-pixel-format-conversion.c @@ -0,0 +1,163 @@ +/* + * Authored By Niels De Graef + * + * 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 . + */ + +#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 + * + * Copyright (C) 2018 Barco NV + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef __COGL_PIXEL_FORMAT_CONVERSION_H__ +#define __COGL_PIXEL_FORMAT_CONVERSION_H__ + +#include "cogl/cogl-types.h" +#include "cogl/cogl-pipeline.h" + +G_BEGIN_DECLS + +/** + * SECTION:cogl-color-space-conversion + * @title: CoglPixelFormatConversion + * @short_description: A collection of snippets to handle pixel_format conversion + * + * In some use cases, one might generate non-RGBA textures (e.g. YUV), which is + * problematic if you then have to composite them in to an RGBA framebuffer. In + * comes #CoglPixelFormatConversion, which you can attach to a #CoglPipeline to + * do this all for you. Internally, it consists of nothing more than a + * collection of #CoglSnippets which do the right thing for you. + */ + +typedef struct _CoglPixelFormatConversion CoglPixelFormatConversion; +#define COGL_PIXEL_FORMAT_CONVERSION(ptr) ((CoglPixelFormatConversion *) ptr) + + +/** + * cogl_multiplane_texture_get_gtype: + * + * Returns: a #GType that can be used with the GLib type system. + */ +GType cogl_pixel_format_conversion_get_gtype (void); + +/* + * cogl_is_pixel_format_conversion: + * @object: A #CoglObject pointer + * + * Gets whether the given @object references an existing + * CoglPixelFormatConversion. + * + * Return value: %TRUE if the @object references a #CoglPixelFormatConversion, + * %FALSE otherwise + */ +gboolean +cogl_is_pixel_format_conversion (void *object); + +/** + * cogl_pixel_format_conversion_new: + * @format: The input format + * + * Creates a #CoglPixelFormatConversion to convert the given @formatro RGBA. If + * no such conversion is needed, it will return %NULL. + * + * Returns: (transfer full) (nullable): A new #CoglPixelFormatConversion, or + * %NULL if none is needed. + */ +CoglPixelFormatConversion * cogl_pixel_format_conversion_new (CoglPixelFormat format); + +/** + * cogl_pixel_format_conversion_attach_to_pipeline: + * @self: The #CoglPixelFormatConversion you want to add + * @pipeline: The #CoglPipeline which needs the color conversion + * @layer: The layer you want to perform the color space conversion at + * + * Adds color conversion to the given @pipeline at the given @layer. + */ +void cogl_pixel_format_conversion_attach_to_pipeline (CoglPixelFormatConversion *self, + CoglPipeline *pipeline, + int layer); + +G_END_DECLS + +#endif diff --git a/cogl/cogl/cogl-pixel-format.c b/cogl/cogl/cogl-pixel-format.c index a8c0857a6..4225c6de1 100644 --- a/cogl/cogl/cogl-pixel-format.c +++ b/cogl/cogl/cogl-pixel-format.c @@ -43,6 +43,7 @@ typedef struct _CoglPixelFormatInfo const char *format_str; int bpp; /* Bytes per pixel */ int aligned; /* Aligned components? (-1 if n/a) */ + uint8_t n_planes; } CoglPixelFormatInfo; static const CoglPixelFormatInfo format_info_table[] = { @@ -50,187 +51,425 @@ static const CoglPixelFormatInfo format_info_table[] = { .cogl_format = COGL_PIXEL_FORMAT_ANY, .format_str = "ANY", .bpp = 0, - .aligned = -1 + .aligned = -1, + .n_planes = 1 }, { .cogl_format = COGL_PIXEL_FORMAT_A_8, .format_str = "A_8", .bpp = 1, - .aligned = 1 + .aligned = 1, + .n_planes = 1 }, { .cogl_format = COGL_PIXEL_FORMAT_RGB_565, .format_str = "RGB_565", .bpp = 2, - .aligned = 0 + .aligned = 0, + .n_planes = 1 }, { .cogl_format = COGL_PIXEL_FORMAT_RGBA_4444, .format_str = "RGBA_4444", .bpp = 2, - .aligned = 0 + .aligned = 0, + .n_planes = 1 }, { .cogl_format = COGL_PIXEL_FORMAT_RGBA_5551, .format_str = "RGBA_5551", .bpp = 2, - .aligned = 0 + .aligned = 0, + .n_planes = 1 }, { .cogl_format = COGL_PIXEL_FORMAT_YUV, .format_str = "YUV", .bpp = 0, - .aligned = -1 + .aligned = -1, + .n_planes = 1 }, { .cogl_format = COGL_PIXEL_FORMAT_G_8, .format_str = "G_8", .bpp = 1, - .aligned = 1 + .aligned = 1, + .n_planes = 1 }, { .cogl_format = COGL_PIXEL_FORMAT_RG_88, .format_str = "RG_88", .bpp = 2, - .aligned = 1 + .aligned = 1, + .n_planes = 1 }, { .cogl_format = COGL_PIXEL_FORMAT_RGB_888, .format_str = "RGB_888", .bpp = 3, - .aligned = 1 + .aligned = 1, + .n_planes = 1 }, { .cogl_format = COGL_PIXEL_FORMAT_BGR_888, .format_str = "BGR_888", .bpp = 3, - .aligned = 1 + .aligned = 1, + .n_planes = 1 }, { .cogl_format = COGL_PIXEL_FORMAT_RGBA_8888, .format_str = "RGBA_8888", .bpp = 4, - .aligned = 1 + .aligned = 1, + .n_planes = 1 }, { .cogl_format = COGL_PIXEL_FORMAT_BGRA_8888, .format_str = "BGRA_8888", .bpp = 4, - .aligned = 1 + .aligned = 1, + .n_planes = 1 }, { .cogl_format = COGL_PIXEL_FORMAT_ARGB_8888, .format_str = "ARGB_8888", .bpp = 4, - .aligned = 1 + .aligned = 1, + .n_planes = 1 }, { .cogl_format = COGL_PIXEL_FORMAT_ABGR_8888, .format_str = "ABGR_8888", .bpp = 4, - .aligned = 1 + .aligned = 1, + .n_planes = 1 }, { .cogl_format = COGL_PIXEL_FORMAT_RGBA_1010102, .format_str = "RGBA_1010102", .bpp = 4, - .aligned = 0 + .aligned = 0, + .n_planes = 1 }, { .cogl_format = COGL_PIXEL_FORMAT_BGRA_1010102, .format_str = "BGRA_1010102", .bpp = 4, - .aligned = 0 + .aligned = 0, + .n_planes = 1 }, { .cogl_format = COGL_PIXEL_FORMAT_ARGB_2101010, .format_str = "ARGB_2101010", .bpp = 4, - .aligned = 0 + .aligned = 0, + .n_planes = 1 }, { .cogl_format = COGL_PIXEL_FORMAT_ABGR_2101010, .format_str = "ABGR_2101010", .bpp = 4, - .aligned = 0 + .aligned = 0, + .n_planes = 1 }, { .cogl_format = COGL_PIXEL_FORMAT_RGBA_8888_PRE, .format_str = "RGBA_8888_PRE", .bpp = 4, - .aligned = 1 + .aligned = 1, + .n_planes = 1 }, { .cogl_format = COGL_PIXEL_FORMAT_BGRA_8888_PRE, .format_str = "BGRA_8888_PRE", .bpp = 4, - .aligned = 1 + .aligned = 1, + .n_planes = 1 }, { .cogl_format = COGL_PIXEL_FORMAT_ARGB_8888_PRE, .format_str = "ARGB_8888_PRE", .bpp = 4, - .aligned = 1 + .aligned = 1, + .n_planes = 1 }, { .cogl_format = COGL_PIXEL_FORMAT_ABGR_8888_PRE, .format_str = "ABGR_8888_PRE", .bpp = 4, - .aligned = 1 + .aligned = 1, + .n_planes = 1 }, { .cogl_format = COGL_PIXEL_FORMAT_RGBA_4444_PRE, .format_str = "RGBA_4444_PRE", .bpp = 2, - .aligned = 0 + .aligned = 0, + .n_planes = 1 }, { .cogl_format = COGL_PIXEL_FORMAT_RGBA_5551_PRE, .format_str = "RGBA_5551_PRE", .bpp = 2, - .aligned = 0 + .aligned = 0, + .n_planes = 1 }, { .cogl_format = COGL_PIXEL_FORMAT_RGBA_1010102_PRE, .format_str = "RGBA_1010102_PRE", .bpp = 4, - .aligned = 0 + .aligned = 0, + .n_planes = 1 }, { .cogl_format = COGL_PIXEL_FORMAT_BGRA_1010102_PRE, .format_str = "BGRA_1010102_PRE", .bpp = 4, - .aligned = 0 + .aligned = 0, + .n_planes = 1 }, { .cogl_format = COGL_PIXEL_FORMAT_ARGB_2101010_PRE, .format_str = "ARGB_2101010_PRE", .bpp = 4, - .aligned = 0 + .aligned = 0, + .n_planes = 1 }, { .cogl_format = COGL_PIXEL_FORMAT_ABGR_2101010_PRE, .format_str = "ABGR_2101010_PRE", .bpp = 4, - .aligned = 0 + .aligned = 0, + .n_planes = 1 }, { .cogl_format = COGL_PIXEL_FORMAT_DEPTH_16, .format_str = "DEPTH_16", .bpp = 2, - .aligned = 1 + .aligned = 1, + .n_planes = 1 }, { .cogl_format = COGL_PIXEL_FORMAT_DEPTH_32, .format_str = "DEPTH_32", .bpp = 4, - .aligned = 1 + .aligned = 1, + .n_planes = 1 }, { .cogl_format = COGL_PIXEL_FORMAT_DEPTH_24_STENCIL_8, .format_str = "DEPTH_24_STENCIL_8", .bpp = 4, - .aligned = 1 + .aligned = 1, + .n_planes = 1 + }, + /* Packed YUV */ + { + .cogl_format = COGL_PIXEL_FORMAT_YUYV, + .format_str = "YUYV", + .bpp = -1, + .aligned = 0, + .n_planes = 2 + }, + { + .cogl_format = COGL_PIXEL_FORMAT_YVYU, + .format_str = "YVYU", + .bpp = -1, + .aligned = 0, + .n_planes = 2 + }, + { + .cogl_format = COGL_PIXEL_FORMAT_UYVY, + .format_str = "UYVY", + .bpp = -1, + .aligned = 0, + .n_planes = 2 + }, + { + .cogl_format = COGL_PIXEL_FORMAT_VYUY, + .format_str = "VYUY", + .bpp = -1, + .aligned = 0, + .n_planes = 2 + }, + { + .cogl_format = COGL_PIXEL_FORMAT_AYUV, + .format_str = "AYUV", + .bpp = -1, + .aligned = 0, + .n_planes = 2 + }, + /* 2 plane RGB + A */ + { + .cogl_format = COGL_PIXEL_FORMAT_XRGB88888_A8, + .format_str = "XRGB88888_A8", + .bpp = -1, + .aligned = 0, + .n_planes = 2 + }, + { + .cogl_format = COGL_PIXEL_FORMAT_XBGR88888_A8, + .format_str = "XBGR88888_A8", + .bpp = -1, + .aligned = 0, + .n_planes = 2 + }, + { + .cogl_format = COGL_PIXEL_FORMAT_RGBX88888_A8, + .format_str = "RGBX88888_A8", + .bpp = -1, + .aligned = 0, + .n_planes = 2 + }, + { + .cogl_format = COGL_PIXEL_FORMAT_BGRX88888_A8, + .format_str = "BGRX88888_A8", + .bpp = -1, + .aligned = 0, + .n_planes = 2 + }, + { + .cogl_format = COGL_PIXEL_FORMAT_RGB888_A8, + .format_str = "RGB888_A8", + .bpp = -1, + .aligned = 0, + .n_planes = 2 + }, + { + .cogl_format = COGL_PIXEL_FORMAT_BGR888_A8, + .format_str = "BGR888_A8", + .bpp = -1, + .aligned = 0, + .n_planes = 2 + }, + { + .cogl_format = COGL_PIXEL_FORMAT_RGB565_A8, + .format_str = "RGB565_A8", + .bpp = -1, + .aligned = 0, + .n_planes = 2 + }, + { + .cogl_format = COGL_PIXEL_FORMAT_BGR565_A8, + .format_str = "BGR565_A8", + .bpp = -1, + .aligned = 0, + .n_planes = 2 + }, + /* 2 plane YUV */ + { + .cogl_format = COGL_PIXEL_FORMAT_NV12, + .format_str = "NV12", + .bpp = -1, + .aligned = 0, + .n_planes = 2 + }, + { + .cogl_format = COGL_PIXEL_FORMAT_NV21, + .format_str = "NV21", + .bpp = -1, + .aligned = 0, + .n_planes = 2 + }, + { + .cogl_format = COGL_PIXEL_FORMAT_NV16, + .format_str = "NV16", + .bpp = -1, + .aligned = 0, + .n_planes = 2 + }, + { + .cogl_format = COGL_PIXEL_FORMAT_NV61, + .format_str = "NV61", + .bpp = -1, + .aligned = 0, + .n_planes = 2 + }, + { + .cogl_format = COGL_PIXEL_FORMAT_NV24, + .format_str = "NV24", + .bpp = -1, + .aligned = 0, + .n_planes = 2 + }, + { + .cogl_format = COGL_PIXEL_FORMAT_NV42, + .format_str = "NV42", + .bpp = -1, + .aligned = 0, + .n_planes = 2 + }, + /* 3 plane YUV */ + { + .cogl_format = COGL_PIXEL_FORMAT_YUV410, + .format_str = "YUV410", + .bpp = -1, + .aligned = 0, + .n_planes = 2 + }, + { + .cogl_format = COGL_PIXEL_FORMAT_YVU410, + .format_str = "YVU410", + .bpp = -1, + .aligned = 0, + .n_planes = 2 + }, + { + .cogl_format = COGL_PIXEL_FORMAT_YUV411, + .format_str = "YUV411", + .bpp = -1, + .aligned = 0, + .n_planes = 2 + }, + { + .cogl_format = COGL_PIXEL_FORMAT_YVU411, + .format_str = "YVU411", + .bpp = -1, + .aligned = 0, + .n_planes = 2 + }, + { + .cogl_format = COGL_PIXEL_FORMAT_YUV420, + .format_str = "YUV420", + .bpp = -1, + .aligned = 0, + .n_planes = 2 + }, + { + .cogl_format = COGL_PIXEL_FORMAT_YVU420, + .format_str = "YVU420", + .bpp = -1, + .aligned = 0, + .n_planes = 2 + }, + { + .cogl_format = COGL_PIXEL_FORMAT_YUV422, + .format_str = "YUV422", + .bpp = -1, + .aligned = 0, + .n_planes = 2 + }, + { + .cogl_format = COGL_PIXEL_FORMAT_YVU422, + .format_str = "YVU422", + .bpp = -1, + .aligned = 0, + .n_planes = 2 + }, + { + .cogl_format = COGL_PIXEL_FORMAT_YUV444, + .format_str = "YUV444", + .bpp = -1, + .aligned = 0, + .n_planes = 2 + }, + { + .cogl_format = COGL_PIXEL_FORMAT_YVU444, + .format_str = "YVU444", + .bpp = -1, + .aligned = 0, + .n_planes = 2 }, }; @@ -268,6 +507,45 @@ _cogl_pixel_format_get_bytes_per_pixel (CoglPixelFormat format) g_assert_not_reached (); } +/* + * 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; + default: + g_warning ("FIXME"); + } + } + 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 @@ -295,6 +573,105 @@ _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 (); +} + +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; + } +} + const char * cogl_pixel_format_to_string (CoglPixelFormat format) { diff --git a/cogl/cogl/cogl-pixel-format.h b/cogl/cogl/cogl-pixel-format.h index c2659fee0..7537e5013 100644 --- a/cogl/cogl/cogl-pixel-format.h +++ b/cogl/cogl/cogl-pixel-format.h @@ -145,7 +145,7 @@ G_BEGIN_DECLS * @COGL_PIXEL_FORMAT_RGB_565: RGB, 16 bits * @COGL_PIXEL_FORMAT_RGBA_4444: RGBA, 16 bits * @COGL_PIXEL_FORMAT_RGBA_5551: RGBA, 16 bits - * @COGL_PIXEL_FORMAT_YUV: Not currently supported + * @COGL_PIXEL_FORMAT_YUV: Obsolete. See the other YUV-based formats. * @COGL_PIXEL_FORMAT_G_8: Single luminance component * @COGL_PIXEL_FORMAT_RGB_888: RGB, 24 bits * @COGL_PIXEL_FORMAT_BGR_888: BGR, 24 bits @@ -167,6 +167,35 @@ G_BEGIN_DECLS * @COGL_PIXEL_FORMAT_BGRA_1010102_PRE: Premultiplied BGRA, 32 bits, 10 bpc * @COGL_PIXEL_FORMAT_ARGB_2101010_PRE: Premultiplied ARGB, 32 bits, 10 bpc * @COGL_PIXEL_FORMAT_ABGR_2101010_PRE: Premultiplied ABGR, 32 bits, 10 bpc + * @COGL_PIXEL_FORMAT_YUYV: YUYV, 32 bits, 16 bpc (Y), 8 bpc (U & V) + * @COGL_PIXEL_FORMAT_YVYU: YVYU, 32 bits, 16 bpc (Y), 8 bpc (V & U) + * @COGL_PIXEL_FORMAT_UYVY: UYVY, 32 bits, 16 bpc (Y), 8 bpc (V & U) + * @COGL_PIXEL_FORMAT_VYUY: VYUV, 32 bits, 16 bpc (Y), 8 bpc (V & U) + * @COGL_PIXEL_FORMAT_AYUV: AYUV, 32 bits, 8 bpc + * @COGL_PIXEL_FORMAT_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 @@ -230,7 +259,50 @@ 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 */ + + /* 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; /* @@ -284,6 +356,29 @@ _cogl_pixel_format_is_endian_dependant (CoglPixelFormat format); #define COGL_PIXEL_FORMAT_CAN_HAVE_PREMULT(format) \ (((format) & COGL_A_BIT) && (format) != COGL_PIXEL_FORMAT_A_8) +/** + * cogl_pixel_format_get_n_planes: + * @format: The format for which to get the number of planes + * + * Returns the number of planes the given CoglPixelFormat specifies. + */ +guint +cogl_pixel_format_get_n_planes (CoglPixelFormat format); + +/** + * cogl_pixel_format_get_subsampling_factors: + * @format: The format to get the subsampling factors from. + * + * Returns the subsampling in both the horizontal as the vertical direction. + */ +void +cogl_pixel_format_get_subsampling_factors (CoglPixelFormat format, + guint *horizontal_factors, + guint *vertical_factors); + +void +cogl_pixel_format_get_bits_per_pixel (CoglPixelFormat format, guint *bpp_out); + /** * cogl_pixel_format_to_string: * @format: a #CoglPixelFormat diff --git a/cogl/cogl/cogl.h b/cogl/cogl/cogl.h index a133e0cba..7aa4fb03e 100644 --- a/cogl/cogl/cogl.h +++ b/cogl/cogl/cogl.h @@ -61,6 +61,7 @@ #include #include #include +#include #include #include #include @@ -112,6 +113,7 @@ #include #include #include +#include #include #include #include diff --git a/cogl/cogl/driver/gl/cogl-texture-2d-gl.c b/cogl/cogl/driver/gl/cogl-texture-2d-gl.c index e36c3523e..cc23f1161 100644 --- a/cogl/cogl/driver/gl/cogl-texture-2d-gl.c +++ b/cogl/cogl/driver/gl/cogl-texture-2d-gl.c @@ -209,6 +209,8 @@ allocate_from_bitmap (CoglTexture2D *tex_2d, GLenum gl_format; GLenum gl_type; + g_warning ("allocate_from_bitmap()"); + internal_format = _cogl_texture_determine_internal_format (tex, cogl_bitmap_get_format (bmp)); @@ -349,6 +351,8 @@ allocate_from_gl_foreign (CoglTexture2D *tex_2d, GLint gl_compressed = GL_FALSE; GLenum gl_int_format = 0; + g_warning ("allocate_from_egl_image_foreign()"); + if (!ctx->texture_driver->allows_foreign_gl_target (ctx, GL_TEXTURE_2D)) { _cogl_set_error (error, diff --git a/cogl/cogl/driver/gl/gl/cogl-driver-gl.c b/cogl/cogl/driver/gl/gl/cogl-driver-gl.c index 4d46844d5..0d3cd0505 100644 --- a/cogl/cogl/driver/gl/gl/cogl-driver-gl.c +++ b/cogl/cogl/driver/gl/gl/cogl-driver-gl.c @@ -268,7 +268,37 @@ _cogl_driver_pixel_format_to_gl (CoglContext *context, break; case COGL_PIXEL_FORMAT_ANY: + /* No support for YUV or multi-plane formats */ case COGL_PIXEL_FORMAT_YUV: + case COGL_PIXEL_FORMAT_YUYV: + case COGL_PIXEL_FORMAT_YVYU: + case COGL_PIXEL_FORMAT_UYVY: + case COGL_PIXEL_FORMAT_VYUY: + case COGL_PIXEL_FORMAT_AYUV: + case COGL_PIXEL_FORMAT_XRGB88888_A8: + case COGL_PIXEL_FORMAT_XBGR88888_A8: + case COGL_PIXEL_FORMAT_RGBX88888_A8: + case COGL_PIXEL_FORMAT_BGRX88888_A8: + case COGL_PIXEL_FORMAT_RGB888_A8: + case COGL_PIXEL_FORMAT_BGR888_A8: + case COGL_PIXEL_FORMAT_RGB565_A8: + case COGL_PIXEL_FORMAT_BGR565_A8: + case COGL_PIXEL_FORMAT_NV12: + case COGL_PIXEL_FORMAT_NV21: + case COGL_PIXEL_FORMAT_NV16: + case COGL_PIXEL_FORMAT_NV61: + case COGL_PIXEL_FORMAT_NV24: + case COGL_PIXEL_FORMAT_NV42: + case COGL_PIXEL_FORMAT_YUV410: + case COGL_PIXEL_FORMAT_YVU410: + case COGL_PIXEL_FORMAT_YUV411: + case COGL_PIXEL_FORMAT_YVU411: + case COGL_PIXEL_FORMAT_YUV420: + case COGL_PIXEL_FORMAT_YVU420: + case COGL_PIXEL_FORMAT_YUV422: + case COGL_PIXEL_FORMAT_YVU422: + case COGL_PIXEL_FORMAT_YUV444: + case COGL_PIXEL_FORMAT_YVU444: g_assert_not_reached (); break; } diff --git a/cogl/cogl/driver/gl/gl/cogl-texture-driver-gl.c b/cogl/cogl/driver/gl/gl/cogl-texture-driver-gl.c index 35b87f7a7..bc27829a1 100644 --- a/cogl/cogl/driver/gl/gl/cogl-texture-driver-gl.c +++ b/cogl/cogl/driver/gl/gl/cogl-texture-driver-gl.c @@ -210,6 +210,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); @@ -314,6 +316,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/driver/gl/gles/cogl-driver-gles.c b/cogl/cogl/driver/gl/gles/cogl-driver-gles.c index 23158d5c7..052867a50 100644 --- a/cogl/cogl/driver/gl/gles/cogl-driver-gles.c +++ b/cogl/cogl/driver/gl/gles/cogl-driver-gles.c @@ -198,7 +198,37 @@ _cogl_driver_pixel_format_to_gl (CoglContext *context, break; case COGL_PIXEL_FORMAT_ANY: + /* No support for YUV or multi-plane formats */ case COGL_PIXEL_FORMAT_YUV: + case COGL_PIXEL_FORMAT_YUYV: + case COGL_PIXEL_FORMAT_YVYU: + case COGL_PIXEL_FORMAT_UYVY: + case COGL_PIXEL_FORMAT_VYUY: + case COGL_PIXEL_FORMAT_AYUV: + case COGL_PIXEL_FORMAT_XRGB88888_A8: + case COGL_PIXEL_FORMAT_XBGR88888_A8: + case COGL_PIXEL_FORMAT_RGBX88888_A8: + case COGL_PIXEL_FORMAT_BGRX88888_A8: + case COGL_PIXEL_FORMAT_RGB888_A8: + case COGL_PIXEL_FORMAT_BGR888_A8: + case COGL_PIXEL_FORMAT_RGB565_A8: + case COGL_PIXEL_FORMAT_BGR565_A8: + case COGL_PIXEL_FORMAT_NV12: + case COGL_PIXEL_FORMAT_NV21: + case COGL_PIXEL_FORMAT_NV16: + case COGL_PIXEL_FORMAT_NV61: + case COGL_PIXEL_FORMAT_NV24: + case COGL_PIXEL_FORMAT_NV42: + case COGL_PIXEL_FORMAT_YUV410: + case COGL_PIXEL_FORMAT_YVU410: + case COGL_PIXEL_FORMAT_YUV411: + case COGL_PIXEL_FORMAT_YVU411: + case COGL_PIXEL_FORMAT_YUV420: + case COGL_PIXEL_FORMAT_YVU420: + case COGL_PIXEL_FORMAT_YUV422: + case COGL_PIXEL_FORMAT_YVU422: + case COGL_PIXEL_FORMAT_YUV444: + case COGL_PIXEL_FORMAT_YVU444: g_assert_not_reached (); break; } diff --git a/cogl/cogl/meson.build b/cogl/cogl/meson.build index 25e86d11e..27707a4c7 100644 --- a/cogl/cogl/meson.build +++ b/cogl/cogl/meson.build @@ -89,6 +89,7 @@ cogl_headers = [ 'cogl-pipeline-state.h', 'cogl-pipeline-layer-state.h', 'cogl-pixel-format.h', + 'cogl-pixel-format-conversion.h', 'cogl-primitives.h', 'cogl-texture.h', 'cogl-texture-2d.h', @@ -126,6 +127,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', @@ -252,10 +254,11 @@ cogl_sources = [ 'cogl-bitmap-pixbuf.c', 'cogl-clip-stack.h', 'cogl-clip-stack.c', - 'cogl-feature-private.h', - 'cogl-feature-private.c', 'cogl-color-private.h', 'cogl-color.c', + 'cogl-pixel-format-conversion.c', + 'cogl-feature-private.c', + 'cogl-feature-private.h', 'cogl-buffer-private.h', 'cogl-buffer.c', 'cogl-pixel-buffer-private.h', @@ -325,6 +328,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 d64e214e5..bfd5f1996 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); } @@ -316,19 +321,26 @@ get_base_pipeline (MetaShapedTexture *stex, CoglContext *ctx) { CoglPipeline *pipeline; + CoglMatrix matrix; + guint n_planes; + 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); + + n_planes = cogl_multi_plane_texture_get_n_planes (stex->texture); + for (i = 0; i < n_planes; 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); + if (!stex->is_y_inverted) { CoglMatrix matrix; @@ -378,8 +390,14 @@ get_base_pipeline (MetaShapedTexture *stex, cogl_pipeline_set_layer_matrix (pipeline, 1, &matrix); } + for (i = 0; i < n_planes + 1; i++) + cogl_pipeline_set_layer_matrix (pipeline, i, &matrix); + if (stex->snippet) - cogl_pipeline_add_layer_snippet (pipeline, 0, stex->snippet); + { + for (i = 0; i < n_planes; i++) + cogl_pipeline_add_layer_snippet (pipeline, i, stex->snippet); + } stex->base_pipeline = pipeline; @@ -398,12 +416,14 @@ 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, + n_layers = cogl_multi_plane_texture_get_n_planes (stex->texture); + cogl_pipeline_set_layer_combine (pipeline, n_layers, "RGBA = MODULATE (PREVIOUS, TEXTURE[A])", NULL); @@ -417,17 +437,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; @@ -507,23 +525,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); + cogl_clear_object (&stex->texture); + stex->texture = planar_tex; - stex->texture = cogl_tex; - - if (cogl_tex != NULL) + if (planar_tex != NULL) { - cogl_object_ref (cogl_tex); - width = cogl_texture_get_width (COGL_TEXTURE (cogl_tex)); - height = cogl_texture_get_height (COGL_TEXTURE (cogl_tex)); + cogl_object_ref (planar_tex); + width = cogl_multi_plane_texture_get_width (planar_tex); + height = cogl_multi_plane_texture_get_height (planar_tex); } else { @@ -539,13 +580,22 @@ 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 (FALSE) */ if (stex->create_mipmaps) - meta_texture_tower_set_base_texture (stex->paint_tower, cogl_tex); + { + meta_texture_tower_set_base_texture (stex->paint_tower, planar_tex); + } } static gboolean @@ -563,10 +613,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; @@ -579,8 +629,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; @@ -686,8 +740,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++) @@ -718,6 +779,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) { @@ -726,16 +788,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); */ - CoglColor color; - cogl_color_init_from_4ub (&color, opacity, opacity, opacity, opacity); - cogl_pipeline_set_color (blended_pipeline, &color); + cogl_pipeline_set_layer_texture (blended_pipeline, i, plane); + cogl_pipeline_set_layer_filters (blended_pipeline, i, filter, filter); + } + + cogl_pipeline_set_color4ub (blended_pipeline, + opacity, opacity, opacity, opacity); if (blended_tex_region) { @@ -778,7 +845,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) @@ -806,6 +873,7 @@ meta_shaped_texture_paint (ClutterActor *actor) * support for TFP textures will result in fallbacks to XGetImage. */ if (stex->create_mipmaps) + /* if (FALSE) */ { int64_t now = g_get_monotonic_time (); int64_t age = now - stex->last_invalidation; @@ -833,11 +901,11 @@ meta_shaped_texture_paint (ClutterActor *actor) } 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 (); @@ -911,7 +979,7 @@ meta_shaped_texture_set_create_mipmaps (MetaShapedTexture *stex, if (create_mipmaps != stex->create_mipmaps) { - CoglTexture *base_texture; + CoglMultiPlaneTexture *base_texture; stex->create_mipmaps = create_mipmaps; base_texture = create_mipmaps ? stex->texture : NULL; meta_texture_tower_set_base_texture (stex->paint_tower, base_texture); @@ -1094,15 +1162,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); } /** @@ -1132,7 +1200,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); } @@ -1143,11 +1211,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; } /** @@ -1244,7 +1313,15 @@ meta_shaped_texture_reset_viewport_dst_size (MetaShapedTexture *stex) static gboolean should_get_via_offscreen (MetaShapedTexture *stex) { - if (!cogl_texture_is_get_data_supported (stex->texture)) + CoglTexture *texture; + + /* If we have more than 1 plane, we can't access the data */ + if (cogl_multi_plane_texture_get_n_planes (stex->texture) > 1) + return TRUE; + + /* We have only 1 plane -> access it directly */ + texture = cogl_multi_plane_texture_get_plane (stex->texture, 0); + if (!cogl_texture_is_get_data_supported (texture)) return TRUE; if (stex->has_viewport_src_rect || stex->has_viewport_dst_size) @@ -1361,19 +1438,19 @@ 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; + CoglTexture *texture; + CoglTexture *mask_texture; cairo_surface_t *surface; g_return_val_if_fail (META_IS_SHAPED_TEXTURE (stex), NULL); - texture = COGL_TEXTURE (stex->texture); - - if (texture == NULL) + if (stex->texture == NULL) return NULL; ensure_size_valid (stex); @@ -1406,6 +1483,9 @@ meta_shaped_texture_get_image (MetaShapedTexture *stex, if (should_get_via_offscreen (stex)) return get_image_via_offscreen (stex, transformed_clip); + /* We know that we only have 1 plane at this point */ + texture = cogl_multi_plane_texture_get_plane (stex->texture, 0); + if (transformed_clip) texture = cogl_texture_new_from_sub_texture (texture, transformed_clip->x, 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/compositor/meta-texture-tower.c b/src/compositor/meta-texture-tower.c index a41cdc89d..bccdd4615 100644 --- a/src/compositor/meta-texture-tower.c +++ b/src/compositor/meta-texture-tower.c @@ -59,8 +59,8 @@ typedef struct struct _MetaTextureTower { int n_levels; - CoglTexture *textures[MAX_TEXTURE_LEVELS]; - CoglOffscreen *fbos[MAX_TEXTURE_LEVELS]; + CoglMultiPlaneTexture *textures[MAX_TEXTURE_LEVELS]; + GList *fbos[MAX_TEXTURE_LEVELS]; Box invalid[MAX_TEXTURE_LEVELS]; CoglPipeline *pipeline_template; }; @@ -113,8 +113,8 @@ meta_texture_tower_free (MetaTextureTower *tower) * unset or until the tower is freed. */ void -meta_texture_tower_set_base_texture (MetaTextureTower *tower, - CoglTexture *texture) +meta_texture_tower_set_base_texture (MetaTextureTower *tower, + CoglMultiPlaneTexture *texture) { int i; @@ -127,22 +127,14 @@ meta_texture_tower_set_base_texture (MetaTextureTower *tower, { for (i = 1; i < tower->n_levels; i++) { - if (tower->textures[i] != NULL) - { - cogl_object_unref (tower->textures[i]); - tower->textures[i] = NULL; - } + cogl_clear_object (&tower->textures[i]); - if (tower->fbos[i] != NULL) - { - cogl_object_unref (tower->fbos[i]); - tower->fbos[i] = NULL; - } + g_list_free_full (tower->fbos[i], cogl_object_unref); + tower->fbos[i] = NULL; } - - cogl_object_unref (tower->textures[0]); } + cogl_clear_object (&tower->textures[0]); tower->textures[0] = texture; if (tower->textures[0] != NULL) @@ -151,8 +143,8 @@ meta_texture_tower_set_base_texture (MetaTextureTower *tower, cogl_object_ref (tower->textures[0]); - width = cogl_texture_get_width (tower->textures[0]); - height = cogl_texture_get_height (tower->textures[0]); + width = cogl_multi_plane_texture_get_width (tower->textures[0]); + height = cogl_multi_plane_texture_get_height (tower->textures[0]); tower->n_levels = 1 + MAX ((int)(M_LOG2E * log (width)), (int)(M_LOG2E * log (height))); tower->n_levels = MIN(tower->n_levels, MAX_TEXTURE_LEVELS); @@ -193,8 +185,8 @@ meta_texture_tower_update_area (MetaTextureTower *tower, if (tower->textures[0] == NULL) return; - texture_width = cogl_texture_get_width (tower->textures[0]); - texture_height = cogl_texture_get_height (tower->textures[0]); + texture_width = cogl_multi_plane_texture_get_width (tower->textures[0]); + texture_height = cogl_multi_plane_texture_get_height (tower->textures[0]); invalid.x1 = x; invalid.y1 = y; @@ -358,23 +350,28 @@ texture_tower_create_texture (MetaTextureTower *tower, int width, int height) { - if ((!is_power_of_two (width) || !is_power_of_two (height)) && - meta_texture_rectangle_check (tower->textures[level - 1])) - { - ClutterBackend *backend = clutter_get_default_backend (); - CoglContext *context = clutter_backend_get_cogl_context (backend); - CoglTextureRectangle *texture_rectangle; + CoglMultiPlaneTexture *base_tex = tower->textures[0]; + GPtrArray *planes; + guint n_planes, i; - texture_rectangle = cogl_texture_rectangle_new_with_size (context, width, height); - tower->textures[level] = COGL_TEXTURE (texture_rectangle); - } - else + n_planes = cogl_multi_plane_texture_get_n_planes (base_tex); + planes = g_ptr_array_new_full (n_planes, cogl_object_unref); + + for (i = 0; i < n_planes; i++) { - tower->textures[level] = cogl_texture_new_with_size (width, height, - COGL_TEXTURE_NO_AUTO_MIPMAP, - TEXTURE_FORMAT); + CoglTexture *texture; + + texture = cogl_texture_new_with_size (width, height, + COGL_TEXTURE_NO_AUTO_MIPMAP, + TEXTURE_FORMAT); + g_ptr_array_add (planes, texture); } + tower->textures[level] = cogl_multi_plane_texture_new ( + cogl_multi_plane_texture_get_format (base_tex), + (CoglTexture **) g_ptr_array_free (planes, FALSE), + n_planes); + tower->invalid[level].x1 = 0; tower->invalid[level].y1 = 0; tower->invalid[level].x2 = width; @@ -385,51 +382,69 @@ static void texture_tower_revalidate (MetaTextureTower *tower, int level) { - CoglTexture *source_texture = tower->textures[level - 1]; - int source_texture_width = cogl_texture_get_width (source_texture); - int source_texture_height = cogl_texture_get_height (source_texture); - CoglTexture *dest_texture = tower->textures[level]; - int dest_texture_width = cogl_texture_get_width (dest_texture); - int dest_texture_height = cogl_texture_get_height (dest_texture); - Box *invalid = &tower->invalid[level]; - CoglFramebuffer *fb; - CoglError *catch_error = NULL; - CoglPipeline *pipeline; + CoglMultiPlaneTexture *src_tex = tower->textures[level - 1]; + int src_width = cogl_multi_plane_texture_get_width (src_tex); + int src_height = cogl_multi_plane_texture_get_height (src_tex); + guint src_tex_n_planes = cogl_multi_plane_texture_get_n_planes (src_tex); + CoglMultiPlaneTexture *dest_tex = tower->textures[level]; + int dest_width = cogl_multi_plane_texture_get_width (dest_tex); + int dest_height = cogl_multi_plane_texture_get_height (dest_tex); + guint i; - if (tower->fbos[level] == NULL) - tower->fbos[level] = cogl_offscreen_new_with_texture (dest_texture); - fb = COGL_FRAMEBUFFER (tower->fbos[level]); - - if (!cogl_framebuffer_allocate (fb, &catch_error)) + /* FIXME: cogl_offscreen_texture_new_with_texture doesn't work for + * multi-plane textures, so we have to make an FBO for each layer */ + for (i = 0; i < src_tex_n_planes; i++) { - cogl_error_free (catch_error); - return; + Box *invalid = &tower->invalid[level]; + CoglTexture *src_plane, *dest_plane; + CoglFramebuffer *fb; + CoglError *catch_error = NULL; + CoglPipeline *pipeline; + + src_plane = cogl_multi_plane_texture_get_plane (src_tex, i); + dest_plane = cogl_multi_plane_texture_get_plane (dest_tex, i); + + if (g_list_nth (tower->fbos[level], i) != NULL) + { + fb = COGL_FRAMEBUFFER (g_list_nth (tower->fbos[level], i)->data); + } + else + { + fb = COGL_FRAMEBUFFER (cogl_offscreen_new_with_texture (dest_plane)); + tower->fbos[level] = g_list_append (tower->fbos[level], fb); + } + + if (!cogl_framebuffer_allocate (fb, &catch_error)) + { + cogl_error_free (catch_error); + return; + } + + cogl_framebuffer_orthographic (fb, 0, 0, dest_width, dest_height, -1., 1.); + + if (!tower->pipeline_template) + { + CoglContext *ctx = + clutter_backend_get_cogl_context (clutter_get_default_backend ()); + tower->pipeline_template = cogl_pipeline_new (ctx); + cogl_pipeline_set_blend (tower->pipeline_template, "RGBA = ADD (SRC_COLOR, 0)", NULL); + } + + pipeline = cogl_pipeline_copy (tower->pipeline_template); + cogl_pipeline_set_layer_texture (pipeline, 0, src_plane); + + cogl_framebuffer_draw_textured_rectangle (fb, pipeline, + invalid->x1, invalid->y1, + invalid->x2, invalid->y2, + (2. * invalid->x1) / src_width, + (2. * invalid->y1) / src_height, + (2. * invalid->x2) / src_width, + (2. * invalid->y2) / src_height); + + cogl_object_unref (pipeline); } - cogl_framebuffer_orthographic (fb, 0, 0, dest_texture_width, dest_texture_height, -1., 1.); - - if (!tower->pipeline_template) - { - CoglContext *ctx = - clutter_backend_get_cogl_context (clutter_get_default_backend ()); - tower->pipeline_template = cogl_pipeline_new (ctx); - cogl_pipeline_set_blend (tower->pipeline_template, "RGBA = ADD (SRC_COLOR, 0)", NULL); - } - - pipeline = cogl_pipeline_copy (tower->pipeline_template); - cogl_pipeline_set_layer_texture (pipeline, 0, tower->textures[level - 1]); - - cogl_framebuffer_draw_textured_rectangle (fb, pipeline, - invalid->x1, invalid->y1, - invalid->x2, invalid->y2, - (2. * invalid->x1) / source_texture_width, - (2. * invalid->y1) / source_texture_height, - (2. * invalid->x2) / source_texture_width, - (2. * invalid->y2) / source_texture_height); - - cogl_object_unref (pipeline); - tower->invalid[level].x1 = tower->invalid[level].x2 = 0; tower->invalid[level].y1 = tower->invalid[level].y2 = 0; } @@ -447,7 +462,7 @@ texture_tower_revalidate (MetaTextureTower *tower, * Return value: the COGL texture handle to use for painting, or * %NULL if no base texture has yet been set. */ -CoglTexture * +CoglMultiPlaneTexture * meta_texture_tower_get_paint_texture (MetaTextureTower *tower) { int texture_width, texture_height; @@ -458,8 +473,8 @@ meta_texture_tower_get_paint_texture (MetaTextureTower *tower) if (tower->textures[0] == NULL) return NULL; - texture_width = cogl_texture_get_width (tower->textures[0]); - texture_height = cogl_texture_get_height (tower->textures[0]); + texture_width = cogl_multi_plane_texture_get_width (tower->textures[0]); + texture_height = cogl_multi_plane_texture_get_height (tower->textures[0]); level = get_paint_level(texture_width, texture_height); if (level < 0) /* singular paint matrix, scaled to nothing */ diff --git a/src/compositor/meta-texture-tower.h b/src/compositor/meta-texture-tower.h index 6a39e4184..9897d93b3 100644 --- a/src/compositor/meta-texture-tower.h +++ b/src/compositor/meta-texture-tower.h @@ -53,14 +53,14 @@ typedef struct _MetaTextureTower MetaTextureTower; MetaTextureTower *meta_texture_tower_new (void); void meta_texture_tower_free (MetaTextureTower *tower); -void meta_texture_tower_set_base_texture (MetaTextureTower *tower, - CoglTexture *texture); +void meta_texture_tower_set_base_texture (MetaTextureTower *tower, + CoglMultiPlaneTexture *texture); void meta_texture_tower_update_area (MetaTextureTower *tower, int x, int y, int width, int height); -CoglTexture *meta_texture_tower_get_paint_texture (MetaTextureTower *tower); +CoglMultiPlaneTexture *meta_texture_tower_get_paint_texture (MetaTextureTower *tower); G_END_DECLS diff --git a/src/compositor/meta-window-actor.c b/src/compositor/meta-window-actor.c index f850cb222..24be20504 100644 --- a/src/compositor/meta-window-actor.c +++ b/src/compositor/meta-window-actor.c @@ -1503,10 +1503,12 @@ build_and_scan_frame_mask (MetaWindowActor *self, guchar *mask_data; guint tex_width, tex_height; MetaShapedTexture *stex; - CoglTexture *paint_tex, *mask_texture; + CoglMultiPlaneTexture *paint_tex; + CoglTexture *mask_texture; int stride; cairo_t *cr; cairo_surface_t *surface; + CoglError *error = NULL; stex = meta_surface_actor_get_texture (priv->surface); g_return_if_fail (stex); @@ -1517,8 +1519,8 @@ build_and_scan_frame_mask (MetaWindowActor *self, if (paint_tex == NULL) return; - tex_width = cogl_texture_get_width (paint_tex); - tex_height = cogl_texture_get_height (paint_tex); + tex_width = cogl_multi_plane_texture_get_width (paint_tex); + tex_height = cogl_multi_plane_texture_get_height (paint_tex); stride = cairo_format_stride_for_width (CAIRO_FORMAT_A8, tex_width); @@ -1559,31 +1561,14 @@ build_and_scan_frame_mask (MetaWindowActor *self, cairo_destroy (cr); cairo_surface_destroy (surface); - if (meta_texture_rectangle_check (paint_tex)) - { - mask_texture = COGL_TEXTURE (cogl_texture_rectangle_new_with_size (ctx, tex_width, tex_height)); - cogl_texture_set_components (mask_texture, COGL_TEXTURE_COMPONENTS_A); - cogl_texture_set_region (mask_texture, - 0, 0, /* src_x/y */ - 0, 0, /* dst_x/y */ - tex_width, tex_height, /* dst_width/height */ - tex_width, tex_height, /* width/height */ - COGL_PIXEL_FORMAT_A_8, - stride, mask_data); - } - else - { - CoglError *error = NULL; + mask_texture = COGL_TEXTURE (cogl_texture_2d_new_from_data (ctx, tex_width, tex_height, + COGL_PIXEL_FORMAT_A_8, + stride, mask_data, &error)); - mask_texture = COGL_TEXTURE (cogl_texture_2d_new_from_data (ctx, tex_width, tex_height, - COGL_PIXEL_FORMAT_A_8, - stride, mask_data, &error)); - - if (error) - { - g_warning ("Failed to allocate mask texture: %s", error->message); - cogl_error_free (error); - } + if (error) + { + g_warning ("Failed to allocate mask texture: %s", error->message); + cogl_error_free (error); } meta_shaped_texture_set_mask_texture (stex, mask_texture); 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..0a7c81f89 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; + 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; + CoglBitmap *bitmap; - g_clear_error (error); + /* 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]); - 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); + g_warning ("Creating plane %d, h_factor = %d, v_factor = %d, offset = %lu", + i, h_factors[i], v_factors[i], offset); - if (!cogl_texture_allocate (new_texture, error)) - g_clear_pointer (&new_texture, cogl_object_unref); - } + 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, + (CoglBitmap **) 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; - if (!texture_2d) - return FALSE; + /* The WL_bind_wayland_display spec states that EGL_NO_CONTEXT is to be + * used in conjunction with the EGL_WAYLAND_BUFFER_WL target. */ + egl_img = meta_egl_create_image (egl, egl_display, EGL_NO_CONTEXT, + EGL_WAYLAND_BUFFER_WL, buffer->resource, + egl_attribs, + error); - buffer->egl_image.texture = COGL_TEXTURE (texture_2d); + 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); + } + + + buffer->egl_image.texture = cogl_multi_plane_texture_new (cogl_format, + (CoglTexture **) 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; + CoglTexture *plane; - 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); + plane = cogl_multi_plane_texture_get_plane (texture, i); - 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)) + 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..877cab736 100644 --- a/src/wayland/meta-wayland-dma-buf.c +++ b/src/wayland/meta-wayland-dma-buf.c @@ -56,8 +56,9 @@ struct _MetaWaylandDmaBufBuffer int width; int height; uint32_t drm_format; - uint64_t drm_modifier; bool is_y_inverted; + + 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 +66,140 @@ 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 EGLImageKHR +create_egl_image_from_dmabuf (MetaEgl *egl, + EGLDisplay egl_display, + MetaWaylandDmaBufBuffer *dma_buf, + int32_t width, + int32_t height, + uint32_t drm_format, + GError **error) +{ + EGLint attribs[64]; + int attr_idx = 0; + + attribs[attr_idx++] = EGL_WIDTH; + attribs[attr_idx++] = width; + attribs[attr_idx++] = EGL_HEIGHT; + attribs[attr_idx++] = height; + attribs[attr_idx++] = EGL_LINUX_DRM_FOURCC_EXT; + attribs[attr_idx++] = drm_format; + + attribs[attr_idx++] = EGL_DMA_BUF_PLANE0_FD_EXT; + attribs[attr_idx++] = dma_buf->fds[0]; + attribs[attr_idx++] = EGL_DMA_BUF_PLANE0_OFFSET_EXT; + attribs[attr_idx++] = dma_buf->offsets[0]; + 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[0] & 0xffffffff; + attribs[attr_idx++] = EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT; + attribs[attr_idx++] = dma_buf->drm_modifier[0] >> 32; + + if (dma_buf->fds[1] >= 0) + { + attribs[attr_idx++] = EGL_DMA_BUF_PLANE1_FD_EXT; + attribs[attr_idx++] = dma_buf->fds[1]; + attribs[attr_idx++] = EGL_DMA_BUF_PLANE1_OFFSET_EXT; + attribs[attr_idx++] = dma_buf->offsets[1]; + 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[1] & 0xffffffff; + attribs[attr_idx++] = EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT; + attribs[attr_idx++] = dma_buf->drm_modifier[1] >> 32; + } + + if (dma_buf->fds[2] >= 0) + { + attribs[attr_idx++] = EGL_DMA_BUF_PLANE2_FD_EXT; + attribs[attr_idx++] = dma_buf->fds[2]; + attribs[attr_idx++] = EGL_DMA_BUF_PLANE2_OFFSET_EXT; + attribs[attr_idx++] = dma_buf->offsets[2]; + 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[2] & 0xffffffff; + attribs[attr_idx++] = EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT; + attribs[attr_idx++] = dma_buf->drm_modifier[2] >> 32; + } + + if (dma_buf->fds[3] >= 0) + { + attribs[attr_idx++] = EGL_DMA_BUF_PLANE3_FD_EXT; + attribs[attr_idx++] = dma_buf->fds[3]; + attribs[attr_idx++] = EGL_DMA_BUF_PLANE3_OFFSET_EXT; + attribs[attr_idx++] = dma_buf->offsets[3]; + 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[3] & 0xffffffff; + attribs[attr_idx++] = EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT; + attribs[attr_idx++] = dma_buf->drm_modifier[3] >> 32; + } + + 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. */ + return meta_egl_create_image (egl, egl_display, EGL_NO_CONTEXT, + EGL_LINUX_DMA_BUF_EXT, NULL, attribs, + error); +} + static gboolean meta_wayland_dma_buf_realize_texture (MetaWaylandBuffer *buffer, GError **error) @@ -76,137 +211,71 @@ 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); + g_warning ("Dmabuf: Got cogl format %s", cogl_pixel_format_to_string (cogl_format)); + 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, + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Unsupported buffer format %d", dma_buf->drm_format); return FALSE; } - attribs[attr_idx++] = EGL_WIDTH; - attribs[attr_idx++] = dma_buf->width; - attribs[attr_idx++] = EGL_HEIGHT; - attribs[attr_idx++] = dma_buf->height; - attribs[attr_idx++] = EGL_LINUX_DRM_FOURCC_EXT; - attribs[attr_idx++] = dma_buf->drm_format; + n_planes = cogl_pixel_format_get_n_planes (cogl_format); + planes = g_ptr_array_new_full (n_planes, cogl_object_unref); - attribs[attr_idx++] = EGL_DMA_BUF_PLANE0_FD_EXT; - attribs[attr_idx++] = dma_buf->fds[0]; - attribs[attr_idx++] = EGL_DMA_BUF_PLANE0_OFFSET_EXT; - attribs[attr_idx++] = dma_buf->offsets[0]; - 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++] = EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT; - attribs[attr_idx++] = dma_buf->drm_modifier >> 32; - - if (dma_buf->fds[1] >= 0) + /* Each EGLImage is a plane in the final CoglMultiPlaneTexture */ + for (i = 0; i < n_planes; i++) { - attribs[attr_idx++] = EGL_DMA_BUF_PLANE1_FD_EXT; - attribs[attr_idx++] = dma_buf->fds[1]; - attribs[attr_idx++] = EGL_DMA_BUF_PLANE1_OFFSET_EXT; - attribs[attr_idx++] = dma_buf->offsets[1]; - 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++] = EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT; - attribs[attr_idx++] = dma_buf->drm_modifier >> 32; + EGLImageKHR egl_img; + CoglTexture2D *plane; + + egl_img = create_egl_image_from_dmabuf (egl, + egl_display, + dma_buf, + dma_buf->width, dma_buf->height, + dma_buf->drm_format, + 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); } - if (dma_buf->fds[2] >= 0) - { - attribs[attr_idx++] = EGL_DMA_BUF_PLANE2_FD_EXT; - attribs[attr_idx++] = dma_buf->fds[2]; - attribs[attr_idx++] = EGL_DMA_BUF_PLANE2_OFFSET_EXT; - attribs[attr_idx++] = dma_buf->offsets[2]; - 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++] = EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT; - attribs[attr_idx++] = dma_buf->drm_modifier >> 32; - } - - if (dma_buf->fds[3] >= 0) - { - attribs[attr_idx++] = EGL_DMA_BUF_PLANE3_FD_EXT; - attribs[attr_idx++] = dma_buf->fds[3]; - attribs[attr_idx++] = EGL_DMA_BUF_PLANE3_OFFSET_EXT; - attribs[attr_idx++] = dma_buf->offsets[3]; - 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++] = EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT; - attribs[attr_idx++] = dma_buf->drm_modifier >> 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; - - texture = cogl_egl_texture_2d_new_from_image (cogl_context, - dma_buf->width, - dma_buf->height, - cogl_format, - egl_image, - error); - - meta_egl_destroy_image (egl, egl_display, egl_image, NULL); - - if (!texture) - return FALSE; - - buffer->dma_buf.texture = COGL_TEXTURE (texture); + buffer->dma_buf.texture = cogl_multi_plane_texture_new (cogl_format, + (CoglTexture **) g_ptr_array_free (planes, FALSE), + 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; @@ -234,7 +303,7 @@ buffer_params_add (struct wl_client *client, drm_modifier |= ((uint64_t) drm_modifier_lo) & 0xffffffff; 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 +311,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 +320,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,8 +329,8 @@ buffer_params_add (struct wl_client *client, return; } - if (dma_buf->drm_modifier != DRM_FORMAT_MOD_INVALID && - dma_buf->drm_modifier != drm_modifier) + if (G_UNLIKELY (dma_buf->drm_modifier[plane_idx] != DRM_FORMAT_MOD_INVALID && + dma_buf->drm_modifier[plane_idx] != drm_modifier)) { wl_resource_post_error (resource, ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_WL_BUFFER, @@ -269,8 +338,9 @@ buffer_params_add (struct wl_client *client, return; } - dma_buf->drm_modifier = drm_modifier; + 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 +620,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 +678,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..a0125894d 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,30 @@ 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 (COGL_PIXEL_FORMAT_ANY, + COGL_TEXTURE (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..02825709d 100644 --- a/src/wayland/meta-wayland.c +++ b/src/wayland/meta-wayland.c @@ -306,6 +306,26 @@ 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_YUV444, + }; + + 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 +338,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