Compare commits

...

5 Commits

Author SHA1 Message Date
Niels De Graef
302128d6bb wip: shm 2020-04-09 15:30:07 +02:00
Niels De Graef
ee17ddc18e wayland: Add support for YUV-based EGLimages 2020-03-30 17:10:57 +02:00
Niels De Graef
f11ca9cfaf multi-texture: Add API to have color conversion
Some pixel formats need to be converted to RGB first before they can be
composited onto the RGBA framebuffer. Since we have absolutely no
intention of doing this on the CPU (killing any kind of performance on
video), we write shaders to do this for us. MetaShapedTexture is then
extended to use this on its base pipeline.
2020-03-30 17:10:57 +02:00
Niels De Graef
c2e191fe3f shaped-texture: Start using MetaMultiTexture
To be able to later support more complex YUV formats, we need to make
sure that MetaShapedTexture (the one who will actually render the
texture) can use the MetaMultiTexture class.
2020-03-30 17:10:57 +02:00
Niels De Graef
65a3b13b2f compositor: Add MetaMultiTexture class
In future commits, we want to be able to handle more complex textures,
such as video frames which are encoded in a YUV-pixel format and have
multiple planes (which each map to a separate texture).

To accomplish this, we introduce a new object `MetaMultiTexture`: this
object can deal with more complex formats by handling multiple
`CoglTexture`s. In a later stage, it will be able to add `CoglSnippet`s
to perform e.g. pixel format conversion (for example from YUV to RGBA).
2020-03-30 17:07:58 +02:00
19 changed files with 1521 additions and 272 deletions

View File

@ -0,0 +1,480 @@
/*
* Authored By Niels De Graef <niels.degraef@barco.com>
*
* Copyright (C) 2018 Barco NV
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
/**
* SECTION:meta-multi-texture-format
* @title: MetaMultiTextureFormat
* @short_description: A representation for complex pixel formats
*
* Some pixel formats that are used in the wild are a bit more complex than
* just ARGB and all its variants. For example: a component might be put in a
* different plane (i.e. at a different place in memory). Another example are
* formats that use Y, U, and V components rather than RGB; if we composit them
* onto an RGBA framebuffer, we have to make sure for example that these get
* converted to the right color format first (using e.g. a shader).
*/
#include "meta/meta-multi-texture-format.h"
#include <cogl/cogl.h>
#include <stdlib.h>
#include <string.h>
#define _YUV_TO_RGB(res, y, u, v) \
"vec4 " res ";\n" \
res ".r = (" y ") + 1.59765625 * (" v ");\n" \
res ".g = (" y ") - 0.390625 * (" u ") - 0.8125 * (" v ");\n" \
res ".b = (" y ") + 2.015625 * (" u ");\n" \
res ".a = 1.0;\n"
/* Shader for a single YUV plane */
#define YUV_TO_RGB_FUNC "meta_yuv_to_rgba"
static const char yuv_to_rgb_shader[] =
"vec4\n"
YUV_TO_RGB_FUNC " (vec2 UV)\n"
"{\n"
" vec4 orig_color = texture2D(cogl_sampler0, UV);\n"
" float y = 1.16438356 * (orig_color.r - 0.0625);\n"
" float u = orig_color.g - 0.5;\n"
" float v = orig_color.b - 0.5;\n"
_YUV_TO_RGB ("color", "y", "u", "v")
" return color;\n"
"}\n";
/* Shader for 1 Y-plane and 1 UV-plane */
#define Y_UV_TO_RGB_FUNC "meta_y_uv_to_rgba"
static const char y_uv_to_rgb_shader[] =
"vec4\n"
Y_UV_TO_RGB_FUNC "(vec2 UV)\n"
"{\n"
" float y = 1.1640625 * (texture2D (cogl_sampler0, UV).x - 0.0625);\n"
" vec2 uv = texture2D (cogl_sampler1, UV).rg;\n"
" uv -= 0.5;\n"
" float u = uv.x;\n"
" float v = uv.y;\n"
_YUV_TO_RGB ("color", "y", "u", "v")
" return color;\n"
"}\n";
/* Shader for 1 Y-plane, 1 U-plane and 1 V-plane */
#define Y_U_V_TO_RGB_FUNC "meta_y_u_v_to_rgba"
static const char y_u_v_to_rgb_shader[] =
"vec4\n"
Y_U_V_TO_RGB_FUNC "(vec2 UV)\n"
"{\n"
" float y = 1.16438356 * (texture2D(cogl_sampler0, UV).x - 0.0625);\n"
" float u = texture2D(cogl_sampler1, UV).x - 0.5;\n"
" float v = texture2D(cogl_sampler2, UV).x - 0.5;\n"
_YUV_TO_RGB ("color", "y", "u", "v")
" return color;\n"
"}\n";
typedef struct _MetaMultiTextureFormatInfo
{
MetaMultiTextureFormat multi_format;
uint8_t n_planes;
/* Per plane-information */
uint8_t bpp[COGL_PIXEL_FORMAT_MAX_PLANES]; /* Bytes per pixel (without subsampling) */
uint8_t hsub[COGL_PIXEL_FORMAT_MAX_PLANES]; /* horizontal subsampling */
uint8_t vsub[COGL_PIXEL_FORMAT_MAX_PLANES]; /* vertical subsampling */
CoglPixelFormat subformats[COGL_PIXEL_FORMAT_MAX_PLANES]; /* influences how we deal with it on a GL level */
/* Shaders */
const char *rgb_shaderfunc; /* Shader name to convert to RGBA (or NULL) */
const char *rgb_shader; /* Shader to convert to RGBA (or NULL) */
} MetaMultiTextureFormatInfo;
/* NOTE: The actual enum values are used as the index, so you don't need to
* loop over the table */
static MetaMultiTextureFormatInfo multi_format_table[] = {
/* Simple */
{
.n_planes = 1,
.bpp = { 4 },
.hsub = { 1 },
.vsub = { 1 },
.subformats = { COGL_PIXEL_FORMAT_ANY },
.rgb_shaderfunc = NULL,
.rgb_shader = NULL,
},
/* Packed YUV */
{ /* YUYV */
.n_planes = 1,
.bpp = { 4 },
.hsub = { 1 },
.vsub = { 1 },
.subformats = { COGL_PIXEL_FORMAT_ARGB_8888 },
.rgb_shaderfunc = YUV_TO_RGB_FUNC,
.rgb_shader = yuv_to_rgb_shader,
},
{ /* YVYU */
.n_planes = 1,
.bpp = { 4 },
.hsub = { 1 },
.vsub = { 1 },
.subformats = { COGL_PIXEL_FORMAT_ARGB_8888 },
.rgb_shaderfunc = YUV_TO_RGB_FUNC,
.rgb_shader = yuv_to_rgb_shader,
},
{ /* UYVY */
.n_planes = 1,
.bpp = { 4 },
.hsub = { 1 },
.vsub = { 1 },
.subformats = { COGL_PIXEL_FORMAT_ARGB_8888 },
.rgb_shaderfunc = YUV_TO_RGB_FUNC,
.rgb_shader = yuv_to_rgb_shader,
},
{ /* VYUY */
.n_planes = 1,
.bpp = { 4 },
.hsub = { 1 },
.vsub = { 1 },
.subformats = { COGL_PIXEL_FORMAT_ARGB_8888 },
.rgb_shaderfunc = YUV_TO_RGB_FUNC,
.rgb_shader = yuv_to_rgb_shader,
},
{ /* AYUV */
.n_planes = 1,
.bpp = { 4 },
.hsub = { 1 },
.vsub = { 1 },
.subformats = { COGL_PIXEL_FORMAT_ARGB_8888 },
.rgb_shaderfunc = YUV_TO_RGB_FUNC,
.rgb_shader = yuv_to_rgb_shader,
},
/* 2 plane RGB + A */
{ /* XRGB8888_A8 */
.n_planes = 2,
.bpp = { 4, 1 },
.hsub = { 1, 1 },
.vsub = { 1, 1 },
.subformats = { COGL_PIXEL_FORMAT_ARGB_8888, COGL_PIXEL_FORMAT_A_8 },
.rgb_shaderfunc = NULL,
.rgb_shader = NULL,
},
{ /* XBGR8888_A8 */
.n_planes = 2,
.bpp = { 4, 1 },
.hsub = { 1, 1 },
.vsub = { 1, 1 },
.subformats = { COGL_PIXEL_FORMAT_ABGR_8888, COGL_PIXEL_FORMAT_A_8 },
.rgb_shaderfunc = NULL,
.rgb_shader = NULL,
},
{ /* RGBX8888_A8 */
.n_planes = 2,
.bpp = { 4, 1 },
.hsub = { 1, 1 },
.vsub = { 1, 1 },
.subformats = { COGL_PIXEL_FORMAT_RGBA_8888, COGL_PIXEL_FORMAT_A_8 },
.rgb_shaderfunc = NULL,
.rgb_shader = NULL,
},
{ /* BGRX8888_A8 */
.n_planes = 2,
.bpp = { 4, 1 },
.hsub = { 1, 1 },
.vsub = { 1, 1 },
.subformats = { COGL_PIXEL_FORMAT_BGRA_8888, COGL_PIXEL_FORMAT_A_8 },
.rgb_shaderfunc = NULL,
.rgb_shader = NULL,
},
{ /* RGB888_A8 */
.n_planes = 2,
.bpp = { 3, 1 },
.hsub = { 1, 1 },
.vsub = { 1, 1 },
.subformats = { COGL_PIXEL_FORMAT_RGB_888, COGL_PIXEL_FORMAT_A_8 },
.rgb_shaderfunc = NULL,
.rgb_shader = NULL,
},
{ /* BGR888_A8 */
.n_planes = 2,
.bpp = { 3, 1 },
.hsub = { 1, 1 },
.vsub = { 1, 1 },
.subformats = { COGL_PIXEL_FORMAT_BGR_888, COGL_PIXEL_FORMAT_A_8 },
.rgb_shaderfunc = NULL,
.rgb_shader = NULL,
},
{ /* RGB565_A8 */
.n_planes = 2,
.bpp = { 2, 1 },
.hsub = { 1, 1 },
.vsub = { 1, 1 },
.subformats = { COGL_PIXEL_FORMAT_RGB_565, COGL_PIXEL_FORMAT_A_8 },
.rgb_shaderfunc = NULL,
.rgb_shader = NULL,
},
{ /* BGR565_A8 */
.n_planes = 2,
.bpp = { 2, 1 },
.hsub = { 1, 1 },
.vsub = { 1, 1 },
.subformats = { COGL_PIXEL_FORMAT_RGB_565, COGL_PIXEL_FORMAT_A_8 },
.rgb_shaderfunc = NULL,
.rgb_shader = NULL,
},
/* 2 plane YUV */
{ /* NV12 */
.n_planes = 2,
.bpp = { 1, 2 },
.hsub = { 1, 2 },
.vsub = { 1, 2 },
.subformats = { COGL_PIXEL_FORMAT_G_8, COGL_PIXEL_FORMAT_RG_88 },
.rgb_shaderfunc = Y_UV_TO_RGB_FUNC,
.rgb_shader = y_uv_to_rgb_shader,
},
{ /* NV21 */
.n_planes = 2,
.bpp = { 1, 2 },
.hsub = { 1, 2 },
.vsub = { 1, 2 },
.subformats = { COGL_PIXEL_FORMAT_G_8, COGL_PIXEL_FORMAT_RG_88 },
.rgb_shaderfunc = Y_UV_TO_RGB_FUNC,
.rgb_shader = y_uv_to_rgb_shader,
},
{ /* NV16 */
.n_planes = 2,
.bpp = { 1, 2 },
.hsub = { 1, 2 },
.vsub = { 1, 1 },
.subformats = { COGL_PIXEL_FORMAT_G_8, COGL_PIXEL_FORMAT_RG_88 },
.rgb_shaderfunc = Y_UV_TO_RGB_FUNC,
.rgb_shader = y_uv_to_rgb_shader,
},
{ /* NV61 */
.n_planes = 2,
.bpp = { 1, 2 },
.hsub = { 1, 2 },
.vsub = { 1, 1 },
.subformats = { COGL_PIXEL_FORMAT_G_8, COGL_PIXEL_FORMAT_RG_88 },
.rgb_shaderfunc = Y_UV_TO_RGB_FUNC,
.rgb_shader = y_uv_to_rgb_shader,
},
{ /* NV24 */
.n_planes = 2,
.bpp = { 1, 2 },
.hsub = { 1, 1 },
.vsub = { 1, 1 },
.subformats = { COGL_PIXEL_FORMAT_G_8, COGL_PIXEL_FORMAT_RG_88 },
.rgb_shaderfunc = Y_UV_TO_RGB_FUNC,
.rgb_shader = y_uv_to_rgb_shader,
},
{ /* NV42 */
.n_planes = 2,
.bpp = { 1, 2 },
.hsub = { 1, 1 },
.vsub = { 1, 1 },
.subformats = { COGL_PIXEL_FORMAT_G_8, COGL_PIXEL_FORMAT_RG_88 },
.rgb_shaderfunc = Y_UV_TO_RGB_FUNC,
.rgb_shader = y_uv_to_rgb_shader,
},
/* 3 plane YUV */
{ /* YUV410 */
.n_planes = 3,
.bpp = { 1, 1, 1 },
.hsub = { 1, 4, 4 },
.vsub = { 1, 4, 4 },
.subformats = { COGL_PIXEL_FORMAT_G_8, COGL_PIXEL_FORMAT_G_8, COGL_PIXEL_FORMAT_G_8 },
.rgb_shaderfunc = Y_U_V_TO_RGB_FUNC,
.rgb_shader = y_u_v_to_rgb_shader,
},
{ /* YVU410 */
.n_planes = 3,
.bpp = { 1, 1, 1 },
.hsub = { 1, 4, 4 },
.vsub = { 1, 4, 4 },
.subformats = { COGL_PIXEL_FORMAT_G_8, COGL_PIXEL_FORMAT_G_8, COGL_PIXEL_FORMAT_G_8 },
.rgb_shaderfunc = Y_U_V_TO_RGB_FUNC,
.rgb_shader = y_u_v_to_rgb_shader,
},
{ /* YUV411 */
.n_planes = 3,
.bpp = { 1, 1, 1 },
.hsub = { 1, 4, 4 },
.vsub = { 1, 1, 1 },
.subformats = { COGL_PIXEL_FORMAT_G_8, COGL_PIXEL_FORMAT_G_8, COGL_PIXEL_FORMAT_G_8 },
.rgb_shaderfunc = Y_U_V_TO_RGB_FUNC,
.rgb_shader = y_u_v_to_rgb_shader,
},
{ /* YVU411 */
.n_planes = 3,
.bpp = { 1, 1, 1 },
.hsub = { 1, 4, 4 },
.vsub = { 1, 1, 1 },
.subformats = { COGL_PIXEL_FORMAT_G_8, COGL_PIXEL_FORMAT_G_8, COGL_PIXEL_FORMAT_G_8 },
.rgb_shaderfunc = Y_U_V_TO_RGB_FUNC,
.rgb_shader = y_u_v_to_rgb_shader,
},
{ /* YUV420 */
.n_planes = 3,
.bpp = { 1, 1, 1 },
.hsub = { 1, 2, 2 },
.vsub = { 1, 2, 2 },
.subformats = { COGL_PIXEL_FORMAT_G_8, COGL_PIXEL_FORMAT_G_8, COGL_PIXEL_FORMAT_G_8 },
.rgb_shaderfunc = Y_U_V_TO_RGB_FUNC,
.rgb_shader = y_u_v_to_rgb_shader,
},
{ /* YVU420 */
.n_planes = 3,
.bpp = { 1, 1, 1 },
.hsub = { 1, 2, 2 },
.vsub = { 1, 2, 2 },
.subformats = { COGL_PIXEL_FORMAT_G_8, COGL_PIXEL_FORMAT_G_8, COGL_PIXEL_FORMAT_G_8 },
.rgb_shaderfunc = Y_U_V_TO_RGB_FUNC,
.rgb_shader = y_u_v_to_rgb_shader,
},
{ /* YUV422 */
.n_planes = 3,
.bpp = { 1, 1, 1 },
.hsub = { 1, 2, 2 },
.vsub = { 1, 1, 1 },
.subformats = { COGL_PIXEL_FORMAT_G_8, COGL_PIXEL_FORMAT_G_8, COGL_PIXEL_FORMAT_G_8 },
.rgb_shaderfunc = Y_U_V_TO_RGB_FUNC,
.rgb_shader = y_u_v_to_rgb_shader,
},
{ /* YVU422 */
.n_planes = 3,
.bpp = { 1, 1, 1 },
.hsub = { 1, 2, 2 },
.vsub = { 1, 1, 1 },
.subformats = { COGL_PIXEL_FORMAT_G_8, COGL_PIXEL_FORMAT_G_8, COGL_PIXEL_FORMAT_G_8 },
.rgb_shaderfunc = Y_U_V_TO_RGB_FUNC,
.rgb_shader = y_u_v_to_rgb_shader,
},
{ /* YUV444 */
.n_planes = 3,
.bpp = { 1, 1, 1 },
.hsub = { 1, 1, 1 },
.vsub = { 1, 1, 1 },
.subformats = { COGL_PIXEL_FORMAT_G_8, COGL_PIXEL_FORMAT_G_8, COGL_PIXEL_FORMAT_G_8 },
.rgb_shaderfunc = Y_U_V_TO_RGB_FUNC,
.rgb_shader = y_u_v_to_rgb_shader,
},
{ /* YVU444 */
.n_planes = 3,
.bpp = { 1, 1, 1 },
.hsub = { 1, 1, 1 },
.vsub = { 1, 1, 1 },
.subformats = { COGL_PIXEL_FORMAT_G_8, COGL_PIXEL_FORMAT_G_8, COGL_PIXEL_FORMAT_G_8 },
.rgb_shaderfunc = Y_U_V_TO_RGB_FUNC,
.rgb_shader = y_u_v_to_rgb_shader,
},
};
void
meta_multi_texture_format_get_bytes_per_pixel (MetaMultiTextureFormat format,
uint8_t *bpp_out)
{
size_t i;
g_return_if_fail (format < G_N_ELEMENTS (multi_format_table));
for (i = 0; i < multi_format_table[format].n_planes; i++)
bpp_out[i] = multi_format_table[format].bpp[i];
}
int
meta_multi_texture_format_get_n_planes (MetaMultiTextureFormat format)
{
g_return_val_if_fail (format < G_N_ELEMENTS (multi_format_table), 0);
return multi_format_table[format].n_planes;
}
void
meta_multi_texture_format_get_subsampling_factors (MetaMultiTextureFormat format,
uint8_t *horizontal_factors,
uint8_t *vertical_factors)
{
size_t i;
g_return_if_fail (format < G_N_ELEMENTS (multi_format_table));
for (i = 0; i < multi_format_table[format].n_planes; i++)
{
horizontal_factors[i] = multi_format_table[format].hsub[i];
vertical_factors[i] = multi_format_table[format].vsub[i];
}
}
void
meta_multi_texture_format_get_subformats (MetaMultiTextureFormat format,
CoglPixelFormat *formats_out)
{
size_t i;
g_return_if_fail (format < G_N_ELEMENTS (multi_format_table));
for (i = 0; i < multi_format_table[format].n_planes; i++)
formats_out[i] = multi_format_table[format].subformats[i];
}
gboolean
meta_multi_texture_format_needs_shaders (MetaMultiTextureFormat format)
{
g_return_val_if_fail (format < G_N_ELEMENTS (multi_format_table), FALSE);
return multi_format_table[format].rgb_shaderfunc != NULL;
}
gboolean
meta_multi_texture_format_get_snippets (MetaMultiTextureFormat format,
CoglSnippet **vertex_snippet,
CoglSnippet **fragment_snippet,
CoglSnippet **layer_snippet)
{
const char *shader_func;
const char *shader_impl;
g_autofree char *layer_hook = NULL;
g_return_val_if_fail (format < G_N_ELEMENTS (multi_format_table), FALSE);
/* Get the function name; bail out early if we don't need a shader */
shader_func = multi_format_table[format].rgb_shaderfunc;
if (shader_func == NULL)
return FALSE;
shader_impl = multi_format_table[format].rgb_shader;
/* Make sure we actually call the function */
layer_hook = g_strdup_printf ("cogl_layer = %s(cogl_tex_coord0_in.st);\n",
shader_func);
if (vertex_snippet)
*vertex_snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_VERTEX_GLOBALS,
shader_impl,
NULL);
if (fragment_snippet)
*fragment_snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT_GLOBALS,
shader_impl,
NULL);
if (layer_snippet)
*layer_snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_LAYER_FRAGMENT,
NULL,
layer_hook);
return TRUE;
}

View File

@ -0,0 +1,285 @@
/*
* Authored By Niels De Graef <niels.degraef@barco.com>
*
* Copyright (C) 2018 Barco NV
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
/**
* SECTION:meta-multi-texture
* @title: MetaMultiTexture
* @short_description: A texture that can have multiple planes.
*
* #MetaMultiTexture 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 #MetaMultiTexture 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
* #MetaMultiTexture 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 meta_multi_texture_get_width() and its analogous version
* for the height to get the correct size of the texture.
*/
#include "meta/meta-multi-texture.h"
#include "meta/meta-enum-types.h"
struct _MetaMultiTexture
{
GObject parent_instance;
MetaMultiTextureFormat format;
guint n_planes;
CoglTexture **planes;
};
G_DEFINE_TYPE (MetaMultiTexture, meta_multi_texture, G_TYPE_OBJECT);
/**
* meta_multi_texture_get_format:
* @self: a #MetaMultiTexture
*
* Returns the #MetaMultiTextureFormat that is used by this texture.
*
* Returns: The texture format that is used by this #MetaMultiTexture.
*/
MetaMultiTextureFormat
meta_multi_texture_get_format (MetaMultiTexture *self)
{
g_return_val_if_fail (META_IS_MULTI_TEXTURE (self), META_MULTI_TEXTURE_FORMAT_SIMPLE);
return self->format;
}
/**
* meta_multi_texture_is_simple:
* @self: a #MetaMultiTexture
*
* A small function that checks whether the given multi texture uses a "simple"
* format, i.e. one that can be represented by a #CoglPixelFormat.
*
* Returns: Whether the texture format is #META_MULTI_TEXTURE_FORMAT_SIMPLE
*/
gboolean
meta_multi_texture_is_simple (MetaMultiTexture *self)
{
g_return_val_if_fail (META_IS_MULTI_TEXTURE (self), FALSE);
return self->format == META_MULTI_TEXTURE_FORMAT_SIMPLE;
}
/**
* meta_multi_texture_get_n_planes:
* @self: a #MetaMultiTexture
*
* 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 #MetaMultiTexture.
*/
guint
meta_multi_texture_get_n_planes (MetaMultiTexture *self)
{
g_return_val_if_fail (META_IS_MULTI_TEXTURE (self), 0);
return self->n_planes;
}
/**
* meta_multi_texture_get_plane:
* @self: a #MetaMultiTexture
* @index: the index of the plane
*
* Returns the n'th plane of the #MetaMultiTexture. Note that it's a programming
* error to use with an index larger than meta_multi_texture_get_n_planes().
*
* Returns: (transfer none): The plane at the given @index.
*/
CoglTexture *
meta_multi_texture_get_plane (MetaMultiTexture *self, guint index)
{
g_return_val_if_fail (META_IS_MULTI_TEXTURE (self), 0);
g_return_val_if_fail (index < self->n_planes, NULL);
return self->planes[index];
}
/**
* meta_multi_texture_get_width:
* @self: a #MetaMultiTexture
*
* Returns the width of the #MetaMultiTexture. 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.
*/
int
meta_multi_texture_get_width (MetaMultiTexture *self)
{
g_return_val_if_fail (META_IS_MULTI_TEXTURE (self), 0);
return cogl_texture_get_width (self->planes[0]);
}
/**
* meta_multi_texture_get_height:
* @self: a #MetaMultiTexture
*
* Returns the height of the #MetaMultiTexture. 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.
*/
int
meta_multi_texture_get_height (MetaMultiTexture *self)
{
g_return_val_if_fail (META_IS_MULTI_TEXTURE (self), 0);
return cogl_texture_get_height (self->planes[0]);
}
static void
meta_multi_texture_finalize (GObject *object)
{
MetaMultiTexture *self = META_MULTI_TEXTURE (object);
int i;
for (i = 0; i < self->n_planes; i++)
cogl_clear_object (&self->planes[i]);
g_free (self->planes);
G_OBJECT_CLASS (meta_multi_texture_parent_class)->finalize (object);
}
static void
meta_multi_texture_init (MetaMultiTexture *self)
{
}
static void
meta_multi_texture_class_init (MetaMultiTextureClass *klass)
{
GObjectClass *gobj_class = G_OBJECT_CLASS (klass);
gobj_class->finalize = meta_multi_texture_finalize;
}
/**
* meta_multi_texture_new:
* @format: The format of the #MetaMultiTexture
* @planes: (transfer full): The actual planes of the texture
* @n_planes: The number of planes
*
* Creates a #MetaMultiTexture with the given @format. Each of the
* #CoglTexture<!-- -->s represents a plane.
*
* Returns: (transfer full): A new #MetaMultiTexture. Use g_object_unref() when
* you're done with it.
*/
MetaMultiTexture *
meta_multi_texture_new (MetaMultiTextureFormat format,
CoglTexture **planes,
guint n_planes)
{
MetaMultiTexture *self;
g_return_val_if_fail (planes != NULL, NULL);
g_return_val_if_fail (n_planes > 0, NULL);
self = g_object_new (META_TYPE_MULTI_TEXTURE, NULL);
self->format = format;
self->n_planes = n_planes;
self->planes = planes;
return self;
}
/**
* meta_multi_texture_new_simple:
* @plane: (transfer full): The single plane of the texture
*
* Creates a #MetaMultiTexture for a "simple" texture, i.e. with only one
* plane, in a format that can be represented using #CoglPixelFormat.
*
* Returns: (transfer full): A new #MetaMultiTexture. Use g_object_unref() when
* you're done with it.
*/
MetaMultiTexture *
meta_multi_texture_new_simple (CoglTexture *plane)
{
MetaMultiTexture *self;
g_return_val_if_fail (plane != NULL, NULL);
self = g_object_new (META_TYPE_MULTI_TEXTURE, NULL);
self->format = META_MULTI_TEXTURE_FORMAT_SIMPLE;
self->n_planes = 1;
self->planes = g_malloc (sizeof (CoglTexture *));
self->planes[0] = plane;
return self;
}
/**
* meta_multi_texture_to_string:
* @self: a #MetaMultiTexture
*
* 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.
*/
char *
meta_multi_texture_to_string (MetaMultiTexture *self)
{
g_autoptr(GString) str = NULL;
g_autofree char *format_str = NULL;
g_autofree char *ret = NULL;
uint8_t i;
str = g_string_new ("");
g_string_append_printf (str, "MetaMultiTexture (%p) {\n", self);
format_str = g_enum_to_string (META_TYPE_MULTI_TEXTURE_FORMAT, self->format);
g_string_append_printf (str, " .format = %s;\n", format_str);
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];
CoglPixelFormat plane_format = _cogl_texture_get_format (plane);
g_string_append_printf (str, " (%p) { .format = %s },\n",
plane,
cogl_pixel_format_to_string (plane_format));
}
g_string_append (str, " }\n");
g_string_append (str, "}");
ret = g_string_free (g_steal_pointer (&str), FALSE);
return g_steal_pointer (&ret);
}

View File

@ -32,7 +32,7 @@
MetaShapedTexture *meta_shaped_texture_new (void);
void meta_shaped_texture_set_texture (MetaShapedTexture *stex,
CoglTexture *texture);
MetaMultiTexture *multi_texture);
void meta_shaped_texture_set_is_y_inverted (MetaShapedTexture *stex,
gboolean is_y_inverted);
void meta_shaped_texture_set_snippet (MetaShapedTexture *stex,

View File

@ -74,7 +74,7 @@ struct _MetaShapedTexture
MetaTextureTower *paint_tower;
CoglTexture *texture;
MetaMultiTexture *texture;
CoglTexture *mask_texture;
CoglSnippet *snippet;
@ -249,24 +249,31 @@ static CoglPipeline *
get_base_pipeline (MetaShapedTexture *stex,
CoglContext *ctx)
{
guint i, n_planes;
MetaMultiTextureFormat format;
CoglPipeline *pipeline;
CoglMatrix matrix;
if (stex->base_pipeline)
return stex->base_pipeline;
/* We'll add as many layers as there are planes in the multi texture,
* plus an extra one for the mask */
n_planes = meta_multi_texture_get_n_planes (stex->texture);
pipeline = cogl_pipeline_new (ctx);
cogl_pipeline_set_layer_wrap_mode_s (pipeline, 0,
COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE);
cogl_pipeline_set_layer_wrap_mode_t (pipeline, 0,
COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE);
cogl_pipeline_set_layer_wrap_mode_s (pipeline, 1,
COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE);
cogl_pipeline_set_layer_wrap_mode_t (pipeline, 1,
COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE);
for (i = 0; i < 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);
/* Apply Y-inversion if necessary */
if (!stex->is_y_inverted)
{
cogl_matrix_scale (&matrix, 1, -1, 1);
@ -274,6 +281,7 @@ get_base_pipeline (MetaShapedTexture *stex,
cogl_pipeline_set_layer_matrix (pipeline, 0, &matrix);
}
/* Apply transformation if needed */
if (stex->transform != META_MONITOR_TRANSFORM_NORMAL)
{
graphene_euler_t euler;
@ -316,6 +324,7 @@ get_base_pipeline (MetaShapedTexture *stex,
cogl_matrix_translate (&matrix, -0.5, -0.5, 0.0);
}
/* Apply viewport scaling if neeed */
if (stex->has_viewport_src_rect)
{
float scaled_tex_width = stex->tex_width / (float) stex->buffer_scale;
@ -348,9 +357,29 @@ get_base_pipeline (MetaShapedTexture *stex,
0);
}
cogl_pipeline_set_layer_matrix (pipeline, 0, &matrix);
cogl_pipeline_set_layer_matrix (pipeline, 1, &matrix);
for (i = 0; i < n_planes + 1; i++)
cogl_pipeline_set_layer_matrix (pipeline, i, &matrix);
/* Add color conversion shaders if needed */
format = meta_multi_texture_get_format (stex->texture);
if (meta_multi_texture_format_needs_shaders (format))
{
CoglSnippet *vertex_snippet;
CoglSnippet *fragment_snippet;
CoglSnippet *layer_snippet;
meta_multi_texture_format_get_snippets (format,
&vertex_snippet,
&fragment_snippet,
&layer_snippet);
cogl_pipeline_add_snippet (pipeline, vertex_snippet);
cogl_pipeline_add_snippet (pipeline, fragment_snippet);
for (i = 0; i < n_planes; i++)
cogl_pipeline_add_layer_snippet (pipeline, i, layer_snippet);
}
/* And custom external shaders (e.g. for EGLStreams) */
if (stex->snippet)
cogl_pipeline_add_layer_snippet (pipeline, 0, stex->snippet);
@ -371,12 +400,14 @@ get_masked_pipeline (MetaShapedTexture *stex,
CoglContext *ctx)
{
CoglPipeline *pipeline;
guint n_planes;
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_planes = meta_multi_texture_get_n_planes (stex->texture);
cogl_pipeline_set_layer_combine (pipeline, n_planes,
"RGBA = MODULATE (PREVIOUS, TEXTURE[A])",
NULL);
@ -457,18 +488,18 @@ paint_clipped_rectangle_node (MetaShapedTexture *stex,
}
static void
set_cogl_texture (MetaShapedTexture *stex,
CoglTexture *cogl_tex)
set_multi_texture (MetaShapedTexture *stex,
MetaMultiTexture *multi_tex)
{
int width, height;
cogl_clear_object (&stex->texture);
g_clear_object (&stex->texture);
if (cogl_tex != NULL)
if (multi_tex != NULL)
{
stex->texture = cogl_object_ref (cogl_tex);
width = cogl_texture_get_width (COGL_TEXTURE (cogl_tex));
height = cogl_texture_get_height (COGL_TEXTURE (cogl_tex));
stex->texture = g_object_ref (multi_tex);
width = meta_multi_texture_get_width (multi_tex);
height = meta_multi_texture_get_height (multi_tex);
}
else
{
@ -490,7 +521,7 @@ set_cogl_texture (MetaShapedTexture *stex,
* damage. */
if (stex->create_mipmaps)
meta_texture_tower_set_base_texture (stex->paint_tower, cogl_tex);
meta_texture_tower_set_base_texture (stex->paint_tower, multi_tex);
}
static gboolean
@ -522,7 +553,7 @@ static void
do_paint_content (MetaShapedTexture *stex,
ClutterPaintNode *root_node,
ClutterPaintContext *paint_context,
CoglTexture *paint_tex,
MetaMultiTexture *paint_tex,
ClutterActorBox *alloc,
uint8_t opacity)
{
@ -534,6 +565,7 @@ do_paint_content (MetaShapedTexture *stex,
CoglPipelineFilter filter;
CoglFramebuffer *framebuffer;
int sample_width, sample_height;
guint n_planes;
ensure_size_valid (stex);
@ -609,6 +641,8 @@ do_paint_content (MetaShapedTexture *stex,
}
}
n_planes = meta_multi_texture_get_n_planes (paint_tex);
/* First, paint the unblended parts, which are part of the opaque region. */
if (use_opaque_region)
{
@ -620,8 +654,14 @@ do_paint_content (MetaShapedTexture *stex,
CoglPipeline *opaque_pipeline;
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 = meta_multi_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 (stex->opaque_region);
for (i = 0; i < n_rects; i++)
@ -648,6 +688,7 @@ do_paint_content (MetaShapedTexture *stex,
if (!blended_tex_region || !cairo_region_is_empty (blended_tex_region))
{
CoglPipeline *blended_pipeline;
guint i;
if (stex->mask_texture == NULL)
{
@ -656,16 +697,20 @@ do_paint_content (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 = meta_multi_texture_get_plane (paint_tex, i);
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)
{
@ -702,11 +747,11 @@ do_paint_content (MetaShapedTexture *stex,
g_clear_pointer (&blended_tex_region, cairo_region_destroy);
}
static CoglTexture *
select_texture_for_paint (MetaShapedTexture *stex,
static MetaMultiTexture *
select_texture_for_paint (MetaShapedTexture *stex,
ClutterPaintContext *paint_context)
{
CoglTexture *texture = NULL;
MetaMultiTexture *texture = NULL;
int64_t now;
if (!stex->texture)
@ -754,7 +799,7 @@ meta_shaped_texture_paint_content (ClutterContent *content,
{
MetaShapedTexture *stex = META_SHAPED_TEXTURE (content);
ClutterActorBox alloc;
CoglTexture *paint_tex = NULL;
MetaMultiTexture *paint_tex = NULL;
uint8_t opacity;
/* The GL EXT_texture_from_pixmap extension does allow for it to be
@ -817,7 +862,7 @@ meta_shaped_texture_set_create_mipmaps (MetaShapedTexture *stex,
if (create_mipmaps != stex->create_mipmaps)
{
CoglTexture *base_texture;
MetaMultiTexture *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);
@ -964,18 +1009,18 @@ meta_shaped_texture_update_area (MetaShapedTexture *stex,
/**
* meta_shaped_texture_set_texture:
* @stex: The #MetaShapedTexture
* @pixmap: The #CoglTexture to display
* @pixmap: The #MetaMultiTexture to display
*/
void
meta_shaped_texture_set_texture (MetaShapedTexture *stex,
CoglTexture *texture)
MetaMultiTexture *texture)
{
g_return_if_fail (META_IS_SHAPED_TEXTURE (stex));
if (stex->texture == texture)
return;
set_cogl_texture (stex, texture);
set_multi_texture (stex, texture);
}
/**
@ -1016,11 +1061,11 @@ meta_shaped_texture_set_snippet (MetaShapedTexture *stex,
*
* Returns: (transfer none): the unshaped texture
*/
CoglTexture *
MetaMultiTexture *
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;
}
/**
@ -1058,13 +1103,19 @@ meta_shaped_texture_get_opaque_region (MetaShapedTexture *stex)
gboolean
meta_shaped_texture_has_alpha (MetaShapedTexture *stex)
{
CoglTexture *texture;
MetaMultiTexture *multi_texture;
CoglTexture *cogl_texture;
texture = stex->texture;
if (!texture)
multi_texture = stex->texture;
if (!multi_texture)
return TRUE;
switch (cogl_texture_get_components (texture))
/* FIXME: for now we don't support alpha (except simple textures) */
if (meta_multi_texture_get_n_planes (multi_texture) > 1)
return FALSE;
cogl_texture = meta_multi_texture_get_plane (multi_texture, 0);
switch (cogl_texture_get_components (cogl_texture))
{
case COGL_TEXTURE_COMPONENTS_A:
case COGL_TEXTURE_COMPONENTS_RGBA:
@ -1082,12 +1133,12 @@ meta_shaped_texture_has_alpha (MetaShapedTexture *stex)
gboolean
meta_shaped_texture_is_opaque (MetaShapedTexture *stex)
{
CoglTexture *texture;
MetaMultiTexture *multi_texture;
cairo_rectangle_int_t opaque_rect;
texture = stex->texture;
if (!texture)
return FALSE;
multi_texture = stex->texture;
if (!multi_texture)
return TRUE;
if (!meta_shaped_texture_has_alpha (stex))
return TRUE;
@ -1179,7 +1230,13 @@ 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 *cogl_texture;
if (meta_multi_texture_get_n_planes (stex->texture) > 1)
return FALSE;
cogl_texture = meta_multi_texture_get_plane (stex->texture, 0);
if (!cogl_texture_is_get_data_supported (cogl_texture))
return TRUE;
if (stex->has_viewport_src_rect || stex->has_viewport_dst_size)
@ -1322,9 +1379,7 @@ meta_shaped_texture_get_image (MetaShapedTexture *stex,
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);
@ -1367,6 +1422,9 @@ meta_shaped_texture_get_image (MetaShapedTexture *stex,
image_height);
}
/* We know that we only have 1 plane at this point */
texture = meta_multi_texture_get_plane (stex->texture, 0);
if (image_clip)
texture = cogl_texture_new_from_sub_texture (texture,
image_clip->x,

View File

@ -46,7 +46,7 @@ struct _MetaSurfaceActorX11
MetaDisplay *display;
CoglTexture *texture;
MetaMultiTexture *texture;
Pixmap pixmap;
Damage damage;
@ -109,7 +109,7 @@ detach_pixmap (MetaSurfaceActorX11 *self)
self->pixmap = None;
meta_x11_error_trap_pop (display->x11_display);
g_clear_pointer (&self->texture, cogl_object_unref);
g_clear_object (&self->texture);
}
static void
@ -119,23 +119,23 @@ set_pixmap (MetaSurfaceActorX11 *self,
CoglContext *ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
MetaShapedTexture *stex = meta_surface_actor_get_texture (META_SURFACE_ACTOR (self));
GError *error = NULL;
CoglTexture *texture;
CoglTexture *cogl_texture;
g_assert (self->pixmap == None);
self->pixmap = pixmap;
texture = COGL_TEXTURE (cogl_texture_pixmap_x11_new (ctx, self->pixmap, FALSE, &error));
cogl_texture = COGL_TEXTURE (cogl_texture_pixmap_x11_new (ctx, self->pixmap, FALSE, &error));
if (error != NULL)
{
g_warning ("Failed to allocate stex texture: %s", error->message);
g_error_free (error);
}
else if (G_UNLIKELY (!cogl_texture_pixmap_x11_is_using_tfp_extension (COGL_TEXTURE_PIXMAP_X11 (texture))))
else if (G_UNLIKELY (!cogl_texture_pixmap_x11_is_using_tfp_extension (COGL_TEXTURE_PIXMAP_X11 (cogl_texture))))
g_warning ("NOTE: Not using GLX TFP!\n");
self->texture = texture;
meta_shaped_texture_set_texture (stex, texture);
self->texture = meta_multi_texture_new_simple (cogl_texture);
meta_shaped_texture_set_texture (stex, self->texture);
}
static void
@ -192,6 +192,7 @@ meta_surface_actor_x11_process_damage (MetaSurfaceActor *actor,
int x, int y, int width, int height)
{
MetaSurfaceActorX11 *self = META_SURFACE_ACTOR_X11 (actor);
CoglTexturePixmapX11 *pixmap;
self->received_damage = TRUE;
@ -215,8 +216,12 @@ 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),
x, y, width, height);
/* We don't support multi-plane or YUV based formats here */
if (!meta_multi_texture_is_simple (self->texture))
return;
pixmap = COGL_TEXTURE_PIXMAP_X11 (meta_multi_texture_get_plane (self->texture, 0));
cogl_texture_pixmap_x11_update_area (pixmap, x, y, width, height);
}
static void

View File

@ -58,8 +58,8 @@ typedef struct
struct _MetaTextureTower
{
int n_levels;
CoglTexture *textures[MAX_TEXTURE_LEVELS];
CoglOffscreen *fbos[MAX_TEXTURE_LEVELS];
MetaMultiTexture *textures[MAX_TEXTURE_LEVELS];
GList *fbos[MAX_TEXTURE_LEVELS];
Box invalid[MAX_TEXTURE_LEVELS];
CoglPipeline *pipeline_template;
};
@ -113,7 +113,7 @@ meta_texture_tower_free (MetaTextureTower *tower)
*/
void
meta_texture_tower_set_base_texture (MetaTextureTower *tower,
CoglTexture *texture)
MetaMultiTexture *texture)
{
int i;
@ -126,20 +126,12 @@ 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;
}
if (tower->fbos[i] != NULL)
{
cogl_object_unref (tower->fbos[i]);
tower->fbos[i] = NULL;
}
g_clear_object (&tower->textures[i]);
g_list_free_full (tower->fbos[i], cogl_object_unref);
tower->fbos[i] = NULL;
}
cogl_object_unref (tower->textures[0]);
g_object_unref (tower->textures[0]);
}
tower->textures[0] = texture;
@ -148,10 +140,10 @@ meta_texture_tower_set_base_texture (MetaTextureTower *tower,
{
int width, height;
cogl_object_ref (tower->textures[0]);
g_object_ref (tower->textures[0]);
width = cogl_texture_get_width (tower->textures[0]);
height = cogl_texture_get_height (tower->textures[0]);
width = meta_multi_texture_get_width (tower->textures[0]);
height = meta_multi_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);
@ -192,8 +184,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 = meta_multi_texture_get_width (tower->textures[0]);
texture_height = meta_multi_texture_get_height (tower->textures[0]);
invalid.x1 = x;
invalid.y1 = y;
@ -355,9 +347,26 @@ texture_tower_create_texture (MetaTextureTower *tower,
int width,
int height)
{
tower->textures[level] = cogl_texture_new_with_size (width, height,
COGL_TEXTURE_NO_AUTO_MIPMAP,
TEXTURE_FORMAT);
MetaMultiTextureFormat format;
guint i, n_planes;
GPtrArray *planes;
CoglTexture **textures;
format = meta_multi_texture_get_format (tower->textures[0]);
n_planes = meta_multi_texture_format_get_n_planes (format);
planes = g_ptr_array_new_full (n_planes, g_object_unref);
for (i = 0; i < n_planes; i++)
{
CoglTexture *texture;
texture = cogl_texture_new_with_size (width, height,
COGL_TEXTURE_NO_AUTO_MIPMAP,
TEXTURE_FORMAT);
g_ptr_array_add (planes, texture);
}
textures = (CoglTexture **) g_ptr_array_free (planes, FALSE);
tower->textures[level] = meta_multi_texture_new (format, textures, n_planes);
tower->invalid[level].x1 = 0;
tower->invalid[level].y1 = 0;
@ -369,51 +378,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);
MetaMultiTexture *src_tex = tower->textures[level - 1];
int src_width = meta_multi_texture_get_width (src_tex);
int src_height = meta_multi_texture_get_height (src_tex);
guint src_n_planes = meta_multi_texture_get_n_planes (src_tex);
MetaMultiTexture *dest_tex = tower->textures[level];
int dest_width = meta_multi_texture_get_width (dest_tex);
int dest_height = meta_multi_texture_get_height (dest_tex);
Box *invalid = &tower->invalid[level];
CoglFramebuffer *fb;
GError *catch_error = NULL;
CoglPipeline *pipeline;
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_n_planes; i++)
{
g_error_free (catch_error);
return;
Box *invalid = &tower->invalid[level];
CoglTexture *src_plane, *dest_plane;
CoglFramebuffer *fb;
GError *catch_error = NULL;
CoglPipeline *pipeline;
src_plane = meta_multi_texture_get_plane (src_tex, i);
dest_plane = meta_multi_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))
{
g_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;
}
@ -432,8 +459,8 @@ 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 *
meta_texture_tower_get_paint_texture (MetaTextureTower *tower,
MetaMultiTexture *
meta_texture_tower_get_paint_texture (MetaTextureTower *tower,
ClutterPaintContext *paint_context)
{
int texture_width, texture_height;
@ -444,8 +471,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 = meta_multi_texture_get_width (tower->textures[0]);
texture_height = meta_multi_texture_get_height (tower->textures[0]);
level = get_paint_level (paint_context, texture_width, texture_height);
if (level < 0) /* singular paint matrix, scaled to nothing */

View File

@ -24,6 +24,7 @@
#define __META_TEXTURE_TOWER_H__
#include "clutter/clutter.h"
#include <meta/meta-multi-texture.h>
G_BEGIN_DECLS
@ -54,13 +55,13 @@ 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);
MetaMultiTexture *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,
MetaMultiTexture *meta_texture_tower_get_paint_texture (MetaTextureTower *tower,
ClutterPaintContext *paint_context);
G_END_DECLS

View File

@ -302,6 +302,8 @@ mutter_sources = [
'compositor/meta-feedback-actor-private.h',
'compositor/meta-module.c',
'compositor/meta-module.h',
'compositor/meta-multi-texture.c',
'compositor/meta-multi-texture-format.c',
'compositor/meta-plugin.c',
'compositor/meta-plugin-manager.c',
'compositor/meta-plugin-manager.h',

View File

@ -20,6 +20,8 @@ mutter_public_headers = [
'meta-inhibit-shortcuts-dialog.h',
'meta-launch-context.h',
'meta-monitor-manager.h',
'meta-multi-texture.h',
'meta-multi-texture-format.h',
'meta-plugin.h',
'meta-remote-access-controller.h',
'meta-selection.h',

View File

@ -0,0 +1,138 @@
/*
* Authored By Niels De Graef <niels.degraef@barco.com>
*
* Copyright (C) 2018 Barco NV
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#ifndef __META_MULTI_TEXTURE_FORMAT_H__
#define __META_MULTI_TEXTURE_FORMAT_H__
#include <glib.h>
#include <cogl/cogl.h>
#include <meta/common.h>
G_BEGIN_DECLS
/**
* MetaMultiTextureFormat:
* @META_MULTI_TEXTURE_FORMAT_FORMAT_SIMPLE: Any format supported by Cogl (see #CoglPixelFormat)
* @META_MULTI_TEXTURE_FORMAT_FORMAT_YUYV: YUYV, 32 bits, 16 bpc (Y), 8 bpc (U & V)
* @META_MULTI_TEXTURE_FORMAT_FORMAT_YVYU: YVYU, 32 bits, 16 bpc (Y), 8 bpc (V & U)
* @META_MULTI_TEXTURE_FORMAT_FORMAT_UYVY: UYVY, 32 bits, 16 bpc (Y), 8 bpc (V & U)
* @META_MULTI_TEXTURE_FORMAT_FORMAT_VYUY: VYUV, 32 bits, 16 bpc (Y), 8 bpc (V & U)
* @META_MULTI_TEXTURE_FORMAT_FORMAT_AYUV: AYUV, 32 bits, 8 bpc
* @META_MULTI_TEXTURE_FORMAT_FORMAT_XRGB8888_A8: 2 planes: 1 RGB-plane (64-bit), 1 alpha-plane
* @META_MULTI_TEXTURE_FORMAT_FORMAT_XBGR8888_A8: 2 planes: 1 BGR-plane (64-bit), 1 alpha-plane
* @META_MULTI_TEXTURE_FORMAT_FORMAT_RGBX8888_A8: 2 planes: 1 RGB-plane (64-bit), 1 alpha-plane
* @META_MULTI_TEXTURE_FORMAT_FORMAT_BGRX8888_A8: 2 planes: 1 BGR-plane (64-bit), 1 alpha-plane
* @META_MULTI_TEXTURE_FORMAT_FORMAT_RGB888_A8: 2 planes: 1 RGB-plane (32-bit), 1 alpha-plane
* @META_MULTI_TEXTURE_FORMAT_FORMAT_BGR888_A8: 2 planes: 1 BGR-plane (32-bit), 1 alpha-plane
* @META_MULTI_TEXTURE_FORMAT_FORMAT_RGB565_A8: 2 planes: 1 RGB-plane (16-bit), 1 alpha-plane
* @META_MULTI_TEXTURE_FORMAT_FORMAT_BGR565_A8: 2 planes: 1 BGR-plane (16-bit), 1 alpha-plane
* @META_MULTI_TEXTURE_FORMAT_FORMAT_NV12: 2 planes: 1 Y-plane, 1 UV-plane (2x2 subsampled)
* @META_MULTI_TEXTURE_FORMAT_FORMAT_NV21: 2 planes: 1 Y-plane, 1 VU-plane (2x2 subsampled)
* @META_MULTI_TEXTURE_FORMAT_FORMAT_NV16: 2 planes: 1 Y-plane, 1 UV-plane (2x1 subsampled)
* @META_MULTI_TEXTURE_FORMAT_FORMAT_NV61: 2 planes: 1 Y-plane, 1 VU-plane (2x1 subsampled)
* @META_MULTI_TEXTURE_FORMAT_FORMAT_NV24: 2 planes: 1 Y-plane, 1 UV-plane
* @META_MULTI_TEXTURE_FORMAT_FORMAT_NV42: 2 planes: 1 Y-plane, 1 VU-plane
* @META_MULTI_TEXTURE_FORMAT_FORMAT_YUV410: 3 planes: 1 Y-plane, 1 U-plane (4x4 subsampled), 1 V-plane (4x4 subsampled)
* @META_MULTI_TEXTURE_FORMAT_FORMAT_YVU410: 3 planes: 1 Y-plane, 1 V-plane (4x4 subsampled), 1 U-plane (4x4 subsampled)
* @META_MULTI_TEXTURE_FORMAT_FORMAT_YUV411: 3 planes: 1 Y-plane, 1 U-plane (4x1 subsampled), 1 V-plane (4x1 subsampled)
* @META_MULTI_TEXTURE_FORMAT_FORMAT_YVU411: 3 planes: 1 Y-plane, 1 V-plane (4x1 subsampled), 1 U-plane (4x1 subsampled)
* @META_MULTI_TEXTURE_FORMAT_FORMAT_YUV420: 3 planes: 1 Y-plane, 1 U-plane (2x2 subsampled), 1 V-plane (2x2 subsampled)
* @META_MULTI_TEXTURE_FORMAT_FORMAT_YVU420: 3 planes: 1 Y-plane, 1 V-plane (2x2 subsampled), 1 U-plane (2x2 subsampled)
* @META_MULTI_TEXTURE_FORMAT_FORMAT_YUV422: 3 planes: 1 Y-plane, 1 U-plane (2x1 subsampled), 1 V-plane (2x1 subsampled)
* @META_MULTI_TEXTURE_FORMAT_FORMAT_YVU422: 3 planes: 1 Y-plane, 1 V-plane (2x1 subsampled), 1 U-plane (2x1 subsampled)
* @META_MULTI_TEXTURE_FORMAT_FORMAT_YUV444: 3 planes: 1 Y-plane, 1 U-plane, 1 V-plane
* @META_MULTI_TEXTURE_FORMAT_FORMAT_YVU444: 3 planes: 1 Y-plane, 1 V-plane, 1 U-plane
*
* XXX write docs
*/
typedef enum _MetaMultiTextureFormat
{
META_MULTI_TEXTURE_FORMAT_SIMPLE,
/* The following list is somewhat synced with Linux's <drm_fourcc.h> */
/* Packed YUV */
META_MULTI_TEXTURE_FORMAT_YUYV,
META_MULTI_TEXTURE_FORMAT_YVYU,
META_MULTI_TEXTURE_FORMAT_UYVY,
META_MULTI_TEXTURE_FORMAT_VYUY,
META_MULTI_TEXTURE_FORMAT_AYUV,
/* 2 plane RGB + A */
META_MULTI_TEXTURE_FORMAT_XRGB8888_A8,
META_MULTI_TEXTURE_FORMAT_XBGR8888_A8,
META_MULTI_TEXTURE_FORMAT_RGBX8888_A8,
META_MULTI_TEXTURE_FORMAT_BGRX8888_A8,
META_MULTI_TEXTURE_FORMAT_RGB888_A8,
META_MULTI_TEXTURE_FORMAT_BGR888_A8,
META_MULTI_TEXTURE_FORMAT_RGB565_A8,
META_MULTI_TEXTURE_FORMAT_BGR565_A8,
/* 2 plane YUV */
META_MULTI_TEXTURE_FORMAT_NV12,
META_MULTI_TEXTURE_FORMAT_NV21,
META_MULTI_TEXTURE_FORMAT_NV16,
META_MULTI_TEXTURE_FORMAT_NV61,
META_MULTI_TEXTURE_FORMAT_NV24,
META_MULTI_TEXTURE_FORMAT_NV42,
/* 3 plane YUV */
META_MULTI_TEXTURE_FORMAT_YUV410,
META_MULTI_TEXTURE_FORMAT_YVU410,
META_MULTI_TEXTURE_FORMAT_YUV411,
META_MULTI_TEXTURE_FORMAT_YVU411,
META_MULTI_TEXTURE_FORMAT_YUV420,
META_MULTI_TEXTURE_FORMAT_YVU420,
META_MULTI_TEXTURE_FORMAT_YUV422,
META_MULTI_TEXTURE_FORMAT_YVU422,
META_MULTI_TEXTURE_FORMAT_YUV444,
META_MULTI_TEXTURE_FORMAT_YVU444
} MetaMultiTextureFormat;
META_EXPORT
void meta_multi_texture_format_get_bytes_per_pixel (MetaMultiTextureFormat format,
uint8_t *bpp_out);
META_EXPORT
int meta_multi_texture_format_get_n_planes (MetaMultiTextureFormat format);
META_EXPORT
void meta_multi_texture_format_get_subsampling_factors (MetaMultiTextureFormat format,
uint8_t *horizontal_factors,
uint8_t *vertical_factors);
META_EXPORT
void meta_multi_texture_format_get_subformats (MetaMultiTextureFormat format,
CoglPixelFormat *formats_out);
META_EXPORT
gboolean meta_multi_texture_format_needs_shaders (MetaMultiTextureFormat format);
META_EXPORT
gboolean meta_multi_texture_format_get_snippets (MetaMultiTextureFormat format,
CoglSnippet **vertex_snippet,
CoglSnippet **fragment_snippet,
CoglSnippet **layer_snippet);
G_END_DECLS
#endif

View File

@ -0,0 +1,72 @@
/*
* Authored By Niels De Graef <niels.degraef@barco.com>
*
* Copyright (C) 2018 Barco NV
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#ifndef __META_MULTI_TEXTURE_H__
#define __META_MULTI_TEXTURE_H__
#include <glib-object.h>
#include <cogl/cogl.h>
#include <meta/common.h>
#include "meta/meta-multi-texture-format.h"
G_BEGIN_DECLS
#define META_TYPE_MULTI_TEXTURE (meta_multi_texture_get_type ())
META_EXPORT
G_DECLARE_FINAL_TYPE (MetaMultiTexture, meta_multi_texture,
META, MULTI_TEXTURE,
GObject)
META_EXPORT
MetaMultiTexture * meta_multi_texture_new (MetaMultiTextureFormat format,
CoglTexture **planes,
guint n_planes);
META_EXPORT
MetaMultiTexture * meta_multi_texture_new_simple (CoglTexture *plane);
META_EXPORT
MetaMultiTextureFormat meta_multi_texture_get_format (MetaMultiTexture *self);
META_EXPORT
gboolean meta_multi_texture_is_simple (MetaMultiTexture *self);
META_EXPORT
guint meta_multi_texture_get_n_planes (MetaMultiTexture *self);
META_EXPORT
CoglTexture * meta_multi_texture_get_plane (MetaMultiTexture *self,
guint index);
META_EXPORT
int meta_multi_texture_get_width (MetaMultiTexture *self);
META_EXPORT
int meta_multi_texture_get_height (MetaMultiTexture *self);
META_EXPORT
char * meta_multi_texture_to_string (MetaMultiTexture *self);
G_END_DECLS
#endif

View File

@ -28,6 +28,7 @@
#include "clutter/clutter.h"
#include <meta/common.h>
#include <meta/meta-multi-texture.h>
G_BEGIN_DECLS
@ -45,7 +46,7 @@ void meta_shaped_texture_set_create_mipmaps (MetaShapedTexture *stex,
gboolean create_mipmaps);
META_EXPORT
CoglTexture * meta_shaped_texture_get_texture (MetaShapedTexture *stex);
MetaMultiTexture * meta_shaped_texture_get_texture (MetaShapedTexture *stex);
META_EXPORT
void meta_shaped_texture_set_mask_texture (MetaShapedTexture *stex,

View File

@ -155,7 +155,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 = meta_multi_texture_new_simple (COGL_TEXTURE (texture));
buffer->is_y_inverted = meta_wayland_egl_stream_is_y_inverted (stream);
return TRUE;
@ -182,46 +182,53 @@ meta_wayland_buffer_realize (MetaWaylandBuffer *buffer)
}
static void
shm_buffer_get_cogl_pixel_format (struct wl_shm_buffer *shm_buffer,
CoglPixelFormat *format_out,
CoglTextureComponents *components_out)
shm_buffer_get_format (struct wl_shm_buffer *shm_buffer,
MetaMultiTextureFormat *multi_format_out,
CoglPixelFormat *cogl_format_out,
CoglTextureComponents *components_out)
{
CoglPixelFormat format;
MetaMultiTextureFormat multi_format = META_MULTI_TEXTURE_FORMAT_SIMPLE;
CoglPixelFormat cogl_format = COGL_PIXEL_FORMAT_ANY;
CoglTextureComponents components = COGL_TEXTURE_COMPONENTS_RGBA;
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;
cogl_format = COGL_PIXEL_FORMAT_ARGB_8888_PRE;
break;
case WL_SHM_FORMAT_XRGB8888:
format = COGL_PIXEL_FORMAT_ARGB_8888;
cogl_format = COGL_PIXEL_FORMAT_ARGB_8888;
components = COGL_TEXTURE_COMPONENTS_RGB;
break;
#elif G_BYTE_ORDER == G_LITTLE_ENDIAN
case WL_SHM_FORMAT_ARGB8888:
format = COGL_PIXEL_FORMAT_BGRA_8888_PRE;
cogl_format = COGL_PIXEL_FORMAT_BGRA_8888_PRE;
break;
case WL_SHM_FORMAT_XRGB8888:
format = COGL_PIXEL_FORMAT_BGRA_8888;
cogl_format = COGL_PIXEL_FORMAT_BGRA_8888;
components = COGL_TEXTURE_COMPONENTS_RGB;
break;
#endif
case WL_SHM_FORMAT_NV12:
multi_format = META_MULTI_TEXTURE_FORMAT_NV12;
break;
default:
g_warn_if_reached ();
format = COGL_PIXEL_FORMAT_ARGB_8888;
cogl_format = COGL_PIXEL_FORMAT_ARGB_8888;
}
if (format_out)
*format_out = format;
if (multi_format_out)
*multi_format_out = multi_format;
if (cogl_format_out)
*cogl_format_out = cogl_format;
if (components_out)
*components_out = components;
}
static gboolean
shm_buffer_attach (MetaWaylandBuffer *buffer,
CoglTexture **texture,
MetaMultiTexture **texture,
GError **error)
{
MetaBackend *backend = meta_get_backend ();
@ -229,76 +236,139 @@ shm_buffer_attach (MetaWaylandBuffer *buffer,
CoglContext *cogl_context = clutter_backend_get_cogl_context (clutter_backend);
struct wl_shm_buffer *shm_buffer;
int stride, width, height;
CoglPixelFormat format;
MetaMultiTextureFormat multi_format;
CoglTextureComponents components;
CoglBitmap *bitmap;
CoglTexture *new_texture;
uint8_t h_factors[3], v_factors[3], bpp[3];
CoglPixelFormat subformats[3];
guint i, n_planes;
gsize plane_offset = 0;
guint8 *data;
GPtrArray *planes;
shm_buffer = wl_shm_buffer_get (buffer->resource);
/* Query the necessary properties */
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_format (shm_buffer, &multi_format, &subformats[0], &components);
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)
/* Fetch some properties from the pixel format */
n_planes = meta_multi_texture_format_get_n_planes (multi_format);
if (multi_format == META_MULTI_TEXTURE_FORMAT_SIMPLE)
{
buffer->is_y_inverted = TRUE;
return TRUE;
/* In the simple case, we can fall back to CoglPixelFormat */
bpp[0] = cogl_pixel_format_get_bytes_per_pixel (subformats[0], 0);
h_factors[0] = 1; /* No subsampling */
v_factors[0] = 1;
}
else
{
meta_multi_texture_format_get_subformats (multi_format, subformats);
meta_multi_texture_format_get_bytes_per_pixel (multi_format, bpp);
meta_multi_texture_format_get_subsampling_factors (multi_format, h_factors, v_factors);
}
cogl_clear_object (texture);
if (*texture &&
meta_multi_texture_get_width (*texture) == width &&
meta_multi_texture_get_height (*texture) == height &&
meta_multi_texture_get_format (*texture) == multi_format)
{
CoglTexture *cogl_texture = meta_multi_texture_get_plane (*texture, 0);
if (cogl_texture_get_components (cogl_texture) == components &&
_cogl_texture_get_format (cogl_texture) == subformats[0])
{
buffer->is_y_inverted = TRUE;
return TRUE;
}
}
g_clear_object (texture);
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))
planes = 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))
int plane_stride;
CoglBitmap *plane_bitmap;
CoglTexture *plane_texture;
/* Adjust the stride: map to the amount of pixels and calculate how many
* bytes that takes in the current plane */
plane_stride = (stride / bpp[0]) * bpp[i] / h_factors[i];
/* Define the bitmap that of this plane */
plane_bitmap = cogl_bitmap_new_for_data (cogl_context,
width / h_factors[i],
height / v_factors[i],
subformats[i],
plane_stride,
data + plane_offset);
if (!plane_bitmap)
goto failure;
/* Create a texture out of it so we can upload it to the GPU */
plane_texture = COGL_TEXTURE (cogl_texture_2d_new_from_bitmap (plane_bitmap));
/* Separately set the components (necessary for e.g. XRGB, NV12) */
/* cogl_texture_set_components (plane_texture, components[i]); */
if (!cogl_texture_allocate (plane_texture, error))
{
CoglTexture2DSliced *texture_sliced;
cogl_clear_object (&plane_texture);
/* If it didn't work due to an NPOT size, try again with an atlas texture */
if (!g_error_matches (*error, COGL_TEXTURE_ERROR, COGL_TEXTURE_ERROR_SIZE))
{
cogl_object_unref (plane_bitmap);
goto failure;
}
g_clear_error (error);
texture_sliced =
cogl_texture_2d_sliced_new_from_bitmap (bitmap,
cogl_texture_2d_sliced_new_from_bitmap (plane_bitmap,
COGL_TEXTURE_MAX_WASTE);
new_texture = COGL_TEXTURE (texture_sliced);
cogl_texture_set_components (new_texture, components);
plane_texture = COGL_TEXTURE (texture_sliced);
if (!cogl_texture_allocate (new_texture, error))
g_clear_pointer (&new_texture, cogl_object_unref);
/* cogl_texture_set_components (plane_texture, components[i]); */
if (!cogl_texture_allocate (plane_texture, error))
{
cogl_clear_object (&plane_texture);
goto failure;
}
}
g_ptr_array_add (planes, plane_texture);
/* Calculate the next plane start in the buffer (consider subsampling) */
plane_offset += plane_stride * (height / v_factors[i]);
}
cogl_object_unref (bitmap);
*texture = meta_multi_texture_new (multi_format,
(CoglTexture **) g_ptr_array_free (planes, FALSE),
n_planes);
wl_shm_buffer_end_access (shm_buffer);
if (!new_texture)
return FALSE;
*texture = new_texture;
buffer->is_y_inverted = TRUE;
return TRUE;
failure:
wl_shm_buffer_end_access (shm_buffer);
g_ptr_array_free (planes, TRUE);
*texture = NULL;
return FALSE;
}
static gboolean
egl_image_buffer_attach (MetaWaylandBuffer *buffer,
CoglTexture **texture,
MetaMultiTexture **texture,
GError **error)
{
MetaBackend *backend = meta_get_backend ();
@ -307,15 +377,15 @@ egl_image_buffer_attach (MetaWaylandBuffer *buffer,
CoglContext *cogl_context = clutter_backend_get_cogl_context (clutter_backend);
EGLDisplay egl_display = cogl_egl_context_get_egl_display (cogl_context);
int format, width, height, y_inverted;
CoglPixelFormat cogl_format;
EGLImageKHR egl_image;
CoglEglImageFlags flags;
CoglTexture2D *texture_2d;
MetaMultiTextureFormat multi_format = META_MULTI_TEXTURE_FORMAT_SIMPLE;
CoglPixelFormat cogl_format = COGL_PIXEL_FORMAT_ANY;
guint i, n_planes;
GPtrArray *planes;
if (buffer->egl_image.texture)
{
cogl_clear_object (texture);
*texture = cogl_object_ref (buffer->egl_image.texture);
g_clear_object (texture);
*texture = g_object_ref (buffer->egl_image.texture);
return TRUE;
}
@ -339,6 +409,7 @@ egl_image_buffer_attach (MetaWaylandBuffer *buffer,
NULL))
y_inverted = EGL_TRUE;
/* Query the color format */
switch (format)
{
case EGL_TEXTURE_RGB:
@ -347,6 +418,16 @@ 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:
/* Technically it can be anything with a separate Y and UV plane
* but since this is only used for shaders later, it's ok */
multi_format = META_MULTI_TEXTURE_FORMAT_NV12;
break;
case EGL_TEXTURE_Y_U_V_WL:
/* Technically it can be anything with a separate Y and UV plane
* but since this is only used for shaders later, it's ok */
multi_format = META_MULTI_TEXTURE_FORMAT_YUV444;
break;
default:
g_set_error (error, G_IO_ERROR,
G_IO_ERROR_FAILED,
@ -354,41 +435,70 @@ 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;
/* Each EGLImage is a plane in the final texture */
n_planes = meta_multi_texture_format_get_n_planes (multi_format);
planes = g_ptr_array_new_full (n_planes, cogl_object_unref);
flags = COGL_EGL_IMAGE_FLAG_NONE;
texture_2d = cogl_egl_texture_2d_new_from_image (cogl_context,
width, height,
cogl_format,
egl_image,
flags,
error);
g_warning ("Got EGL with format %u", multi_format);
meta_egl_destroy_image (egl, egl_display, egl_image, NULL);
for (i = 0; i < n_planes; i++)
{
EGLint egl_attribs[3];
EGLImageKHR egl_img;
CoglEglImageFlags flags;
CoglTexture2D *texture_2d;
if (!texture_2d)
return FALSE;
/* Specify that we want the i'th plane */
egl_attribs[0] = EGL_WAYLAND_PLANE_WL;
egl_attribs[1] = i;
egl_attribs[2] = EGL_NONE;
buffer->egl_image.texture = COGL_TEXTURE (texture_2d);
/* The WL_bind_wayland_display spec states that EGL_NO_CONTEXT is to be
* used in conjunction with the EGL_WAYLAND_BUFFER_WL target. */
egl_img = meta_egl_create_image (egl, egl_display, EGL_NO_CONTEXT,
EGL_WAYLAND_BUFFER_WL, buffer->resource,
egl_attribs,
error);
if (G_UNLIKELY (egl_img == EGL_NO_IMAGE_KHR))
goto on_error;
flags = COGL_EGL_IMAGE_FLAG_NONE;
texture_2d = cogl_egl_texture_2d_new_from_image (cogl_context,
width, height,
cogl_format,
egl_img,
flags,
error);
meta_egl_destroy_image (egl, egl_display, egl_img, NULL);
if (G_UNLIKELY (!texture_2d))
goto on_error;
g_ptr_array_add (planes, COGL_TEXTURE (texture_2d));
}
buffer->egl_image.texture =
meta_multi_texture_new (multi_format,
(CoglTexture**) g_ptr_array_free (planes, FALSE),
n_planes);
buffer->is_y_inverted = !!y_inverted;
cogl_clear_object (texture);
*texture = cogl_object_ref (buffer->egl_image.texture);
g_clear_object (texture);
*texture = g_object_ref (buffer->egl_image.texture);
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,
MetaMultiTexture **texture,
GError **error)
{
MetaWaylandEglStream *stream = buffer->egl_stream.stream;
@ -398,8 +508,8 @@ egl_stream_buffer_attach (MetaWaylandBuffer *buffer,
if (!meta_wayland_egl_stream_attach (stream, error))
return FALSE;
cogl_clear_object (texture);
*texture = cogl_object_ref (buffer->egl_stream.texture);
g_clear_object (texture);
*texture = g_object_ref (buffer->egl_stream.texture);
return TRUE;
}
@ -408,8 +518,8 @@ egl_stream_buffer_attach (MetaWaylandBuffer *buffer,
/**
* meta_wayland_buffer_attach:
* @buffer: a pointer to a #MetaWaylandBuffer
* @texture: (inout) (transfer full): a #CoglTexture representing the surface
* content
* @texture: (inout) (transfer full): a #MetaMultiTexture representing the
* surface content
* @error: return location for error or %NULL
*
* This function should be passed a pointer to the texture used to draw the
@ -426,7 +536,7 @@ egl_stream_buffer_attach (MetaWaylandBuffer *buffer,
*/
gboolean
meta_wayland_buffer_attach (MetaWaylandBuffer *buffer,
CoglTexture **texture,
MetaMultiTexture **texture,
GError **error)
{
g_return_val_if_fail (buffer->resource, FALSE);
@ -493,56 +603,102 @@ meta_wayland_buffer_is_y_inverted (MetaWaylandBuffer *buffer)
static gboolean
process_shm_buffer_damage (MetaWaylandBuffer *buffer,
CoglTexture *texture,
MetaMultiTexture *texture,
cairo_region_t *region,
GError **error)
{
struct wl_shm_buffer *shm_buffer;
int i, n_rectangles;
gboolean set_texture_failed = FALSE;
CoglPixelFormat format;
MetaMultiTextureFormat multi_format = META_MULTI_TEXTURE_FORMAT_SIMPLE;
CoglTextureComponents components;
const uint8_t *data;
int32_t stride, height;
uint8_t h_factors[3], v_factors[3], bpp[3];
CoglPixelFormat subformats[3];
gsize plane_offset = 0;
guint i, n_planes;
int j, n_rectangles;
n_rectangles = cairo_region_num_rectangles (region);
shm_buffer = wl_shm_buffer_get (buffer->resource);
shm_buffer_get_cogl_pixel_format (shm_buffer, &format, NULL);
g_return_val_if_fail (cogl_pixel_format_get_n_planes (format) == 1, FALSE);
/* 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);
height = wl_shm_buffer_get_height (shm_buffer);
shm_buffer_get_format (shm_buffer, &multi_format, &subformats[0], &components);
/* Fetch some properties from the pixel format */
n_planes = meta_multi_texture_format_get_n_planes (multi_format);
if (multi_format == META_MULTI_TEXTURE_FORMAT_SIMPLE)
{
const uint8_t *data = wl_shm_buffer_get_data (shm_buffer);
int32_t stride = wl_shm_buffer_get_stride (shm_buffer);
cairo_rectangle_int_t rect;
int bpp;
bpp = cogl_pixel_format_get_bytes_per_pixel (format, 0);
cairo_region_get_rectangle (region, i, &rect);
if (!_cogl_texture_set_region (texture,
rect.width, rect.height,
format,
stride,
data + rect.x * bpp + rect.y * stride,
rect.x, rect.y,
0,
error))
{
set_texture_failed = TRUE;
break;
}
/* In the simple case, we can fall back to CoglPixelFormat */
bpp[0] = cogl_pixel_format_get_bytes_per_pixel (subformats[0], 0);
h_factors[0] = 1; /* No subsampling */
v_factors[0] = 1;
}
else
{
meta_multi_texture_format_get_subformats (multi_format, subformats);
meta_multi_texture_format_get_bytes_per_pixel (multi_format, bpp);
meta_multi_texture_format_get_subsampling_factors (multi_format, h_factors, v_factors);
}
wl_shm_buffer_end_access (shm_buffer);
/* Go over each plane and process the regions */
for (i = 0; i < n_planes; i++)
{
CoglTexture *plane;
int plane_stride;
plane = meta_multi_texture_get_plane (texture, i);
plane_stride = (stride / bpp[0]) * bpp[i] / h_factors[i];
for (j = 0; j < n_rectangles; j++)
{
cairo_rectangle_int_t rect;
gsize rect_offset;
cairo_region_get_rectangle (region, j, &rect);
/* It's possible we get a faulty rectangle of size zero: ignore */
if (rect.height == 0 || rect.width == 0)
continue;
rect_offset = plane_offset
+ rect.y * plane_stride / v_factors[i] /* Find the right row */
+ rect.x * bpp[i] / h_factors[i]; /* and the right column */
if (!_cogl_texture_set_region (plane,
rect.width / h_factors[i],
rect.height / v_factors[i],
subformats[i],
plane_stride,
data + rect_offset,
rect.x, rect.y,
0,
error))
{
set_texture_failed = TRUE;
goto out;
}
}
/* Calculate the next plane start in the buffer (consider subsampling) */
plane_offset += plane_stride * (height / v_factors[i]);
}
out:
wl_shm_buffer_end_access (shm_buffer);
return !set_texture_failed;
}
void
meta_wayland_buffer_process_damage (MetaWaylandBuffer *buffer,
CoglTexture *texture,
MetaMultiTexture *texture,
cairo_region_t *region)
{
gboolean res = FALSE;
@ -582,12 +738,12 @@ meta_wayland_buffer_finalize (GObject *object)
{
MetaWaylandBuffer *buffer = META_WAYLAND_BUFFER (object);
g_clear_pointer (&buffer->egl_image.texture, cogl_object_unref);
g_clear_object (&buffer->egl_image.texture);
#ifdef HAVE_WAYLAND_EGLSTREAM
g_clear_pointer (&buffer->egl_stream.texture, cogl_object_unref);
g_clear_object (&buffer->egl_stream.texture);
g_clear_object (&buffer->egl_stream.stream);
#endif
g_clear_pointer (&buffer->dma_buf.texture, cogl_object_unref);
g_clear_object (&buffer->dma_buf.texture);
g_clear_object (&buffer->dma_buf.dma_buf);
G_OBJECT_CLASS (meta_wayland_buffer_parent_class)->finalize (object);

View File

@ -29,6 +29,7 @@
#include <wayland-server.h>
#include "cogl/cogl.h"
#include "meta/meta-multi-texture.h"
#include "wayland/meta-wayland-types.h"
#include "wayland/meta-wayland-egl-stream.h"
#include "wayland/meta-wayland-dma-buf.h"
@ -56,19 +57,19 @@ struct _MetaWaylandBuffer
MetaWaylandBufferType type;
struct {
CoglTexture *texture;
MetaMultiTexture *texture;
} egl_image;
#ifdef HAVE_WAYLAND_EGLSTREAM
struct {
MetaWaylandEglStream *stream;
CoglTexture *texture;
MetaMultiTexture *texture;
} egl_stream;
#endif
struct {
MetaWaylandDmaBufBuffer *dma_buf;
CoglTexture *texture;
MetaMultiTexture *texture;
} dma_buf;
};
@ -81,12 +82,12 @@ struct wl_resource * meta_wayland_buffer_get_resource (MetaWaylandBuff
gboolean meta_wayland_buffer_is_realized (MetaWaylandBuffer *buffer);
gboolean meta_wayland_buffer_realize (MetaWaylandBuffer *buffer);
gboolean meta_wayland_buffer_attach (MetaWaylandBuffer *buffer,
CoglTexture **texture,
MetaMultiTexture **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,
MetaMultiTexture *texture,
cairo_region_t *region);
#endif /* META_WAYLAND_BUFFER_H */

View File

@ -90,7 +90,7 @@ meta_wayland_dma_buf_realize_texture (MetaWaylandBuffer *buffer,
CoglPixelFormat cogl_format;
EGLImageKHR egl_image;
CoglEglImageFlags flags;
CoglTexture2D *texture;
CoglTexture2D *cogl_texture;
if (buffer->dma_buf.texture)
return TRUE;
@ -146,20 +146,20 @@ meta_wayland_dma_buf_realize_texture (MetaWaylandBuffer *buffer,
return FALSE;
flags = COGL_EGL_IMAGE_FLAG_NO_GET_DATA;
texture = cogl_egl_texture_2d_new_from_image (cogl_context,
dma_buf->width,
dma_buf->height,
cogl_format,
egl_image,
flags,
error);
cogl_texture = cogl_egl_texture_2d_new_from_image (cogl_context,
dma_buf->width,
dma_buf->height,
cogl_format,
egl_image,
flags,
error);
meta_egl_destroy_image (egl, egl_display, egl_image, NULL);
if (!texture)
if (!cogl_texture)
return FALSE;
buffer->dma_buf.texture = COGL_TEXTURE (texture);
buffer->dma_buf.texture = meta_multi_texture_new_simple (COGL_TEXTURE (cogl_texture));
buffer->is_y_inverted = dma_buf->is_y_inverted;
return TRUE;
@ -167,14 +167,14 @@ meta_wayland_dma_buf_realize_texture (MetaWaylandBuffer *buffer,
gboolean
meta_wayland_dma_buf_buffer_attach (MetaWaylandBuffer *buffer,
CoglTexture **texture,
MetaMultiTexture **texture,
GError **error)
{
if (!meta_wayland_dma_buf_realize_texture (buffer, error))
return FALSE;
cogl_clear_object (texture);
*texture = cogl_object_ref (buffer->dma_buf.texture);
g_clear_object (texture);
*texture = g_object_ref (buffer->dma_buf.texture);
return TRUE;
}

View File

@ -31,6 +31,7 @@
#include <glib-object.h>
#include "cogl/cogl.h"
#include "meta/meta-multi-texture.h"
#include "wayland/meta-wayland-types.h"
#define META_TYPE_WAYLAND_DMA_BUF_BUFFER (meta_wayland_dma_buf_buffer_get_type ())
@ -43,7 +44,7 @@ gboolean meta_wayland_dma_buf_init (MetaWaylandCompositor *compositor);
gboolean
meta_wayland_dma_buf_buffer_attach (MetaWaylandBuffer *buffer,
CoglTexture **texture,
MetaMultiTexture **texture,
GError **error);
MetaWaylandDmaBufBuffer *

View File

@ -241,7 +241,7 @@ get_buffer_width (MetaWaylandSurface *surface)
MetaWaylandBuffer *buffer = meta_wayland_surface_get_buffer (surface);
if (buffer)
return cogl_texture_get_width (surface->texture);
return meta_multi_texture_get_width (surface->texture);
else
return 0;
}
@ -252,7 +252,7 @@ get_buffer_height (MetaWaylandSurface *surface)
MetaWaylandBuffer *buffer = meta_wayland_surface_get_buffer (surface);
if (buffer)
return cogl_texture_get_height (surface->texture);
return meta_multi_texture_get_height (surface->texture);
else
return 0;
}
@ -658,7 +658,7 @@ meta_wayland_surface_apply_state (MetaWaylandSurface *surface,
}
else
{
cogl_clear_object (&surface->texture);
g_clear_object (&surface->texture);
}
/* If the newly attached buffer is going to be accessed directly without
@ -1277,7 +1277,7 @@ wl_surface_destructor (struct wl_resource *resource)
if (surface->buffer_held)
meta_wayland_surface_unref_buffer_use_count (surface);
g_clear_pointer (&surface->texture, cogl_object_unref);
g_clear_object (&surface->texture);
g_clear_object (&surface->buffer_ref.buffer);
g_clear_object (&surface->cached_state);
@ -1854,7 +1854,7 @@ meta_wayland_surface_is_shortcuts_inhibited (MetaWaylandSurface *surface,
return g_hash_table_contains (surface->shortcut_inhibited_seats, seat);
}
CoglTexture *
MetaMultiTexture *
meta_wayland_surface_get_texture (MetaWaylandSurface *surface)
{
return surface->texture;

View File

@ -153,7 +153,7 @@ struct _MetaWaylandSurface
GHashTable *outputs_to_destroy_notify_id;
MetaMonitorTransform buffer_transform;
CoglTexture *texture;
MetaMultiTexture *texture;
/* Buffer reference state. */
struct {
@ -327,7 +327,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);
MetaMultiTexture * meta_wayland_surface_get_texture (MetaWaylandSurface *surface);
MetaSurfaceActor * meta_wayland_surface_get_actor (MetaWaylandSurface *surface);

View File

@ -306,6 +306,24 @@ 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,
};
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 +336,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