wayland: Support complex (YUV) pixel formats

In the previous commits, we added the possibility to use pixel formats
which are complex (YUV-based and/or multi-planar) inside Cogl. Use this
new feature by assuming we get a CoglMultiPlaneTexture, rather than a
"simple" CoglTexture.

To easily test whether this works, one can use GStreamer pipelines
(you'll need gst-plugins-bad for this to work):

For normal BGRA (this should already work before this commit):

```
$ gst-launch-1.0 videotestsrc ! "video/x-raw" ! waylandsink
```

For NV12 (a popular video format):

```
$ gst-launch-1.0 videotestsrc ! "video/x-raw,format=NV12" ! waylandsink
```

For YUV 4:2:2 (another video format):

```
$ gst-launch-1.0 videotestsrc ! "video/x-raw,format=Y42B" ! waylandsink
```

You can also replace with other video sinks, like `vaapisink`.

`glimagesink` also works, but for some reason seems to unconditionally
convert to RGBA before submitting a texture (so it doesn't do a lot
really).

Fixes https://bugzilla.gnome.org/show_bug.cgi?id=705514
This commit is contained in:
Niels De Graef 2019-06-19 08:21:33 +02:00
parent f8747a2fe2
commit 784b1750c4
19 changed files with 744 additions and 393 deletions

View File

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

View File

@ -89,7 +89,7 @@ struct _MetaShapedTexture
MetaTextureTower *paint_tower; MetaTextureTower *paint_tower;
CoglTexture *texture; CoglMultiPlaneTexture *texture;
CoglTexture *mask_texture; CoglTexture *mask_texture;
CoglSnippet *snippet; CoglSnippet *snippet;
@ -97,6 +97,8 @@ struct _MetaShapedTexture
CoglPipeline *masked_pipeline; CoglPipeline *masked_pipeline;
CoglPipeline *unblended_pipeline; CoglPipeline *unblended_pipeline;
CoglPixelFormatConversion *pixel_format_conversion;
gboolean is_y_inverted; gboolean is_y_inverted;
/* The region containing only fully opaque pixels */ /* The region containing only fully opaque pixels */
@ -277,9 +279,11 @@ set_clip_region (MetaShapedTexture *stex,
static void static void
meta_shaped_texture_reset_pipelines (MetaShapedTexture *stex) meta_shaped_texture_reset_pipelines (MetaShapedTexture *stex)
{ {
g_clear_pointer (&stex->base_pipeline, cogl_object_unref); cogl_clear_object (&stex->pixel_format_conversion);
g_clear_pointer (&stex->masked_pipeline, cogl_object_unref);
g_clear_pointer (&stex->unblended_pipeline, cogl_object_unref); cogl_clear_object (&stex->base_pipeline);
cogl_clear_object (&stex->masked_pipeline);
cogl_clear_object (&stex->unblended_pipeline);
} }
static void static void
@ -297,7 +301,7 @@ meta_shaped_texture_dispose (GObject *object)
meta_texture_tower_free (stex->paint_tower); meta_texture_tower_free (stex->paint_tower);
stex->paint_tower = NULL; stex->paint_tower = NULL;
g_clear_pointer (&stex->texture, cogl_object_unref); cogl_clear_object (&stex->texture);
g_clear_pointer (&stex->opaque_region, cairo_region_destroy); g_clear_pointer (&stex->opaque_region, cairo_region_destroy);
meta_shaped_texture_set_mask_texture (stex, NULL); meta_shaped_texture_set_mask_texture (stex, NULL);
@ -306,7 +310,7 @@ meta_shaped_texture_dispose (GObject *object)
meta_shaped_texture_reset_pipelines (stex); 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); G_OBJECT_CLASS (meta_shaped_texture_parent_class)->dispose (object);
} }
@ -317,19 +321,23 @@ get_base_pipeline (MetaShapedTexture *stex,
{ {
CoglPipeline *pipeline; CoglPipeline *pipeline;
CoglMatrix matrix; CoglMatrix matrix;
CoglPixelFormat format;
uint8_t i, n_planes;
if (stex->base_pipeline) if (stex->base_pipeline)
return stex->base_pipeline; return stex->base_pipeline;
pipeline = cogl_pipeline_new (ctx); pipeline = cogl_pipeline_new (ctx);
cogl_pipeline_set_layer_wrap_mode_s (pipeline, 0,
COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE); format = cogl_multi_plane_texture_get_format (stex->texture);
cogl_pipeline_set_layer_wrap_mode_t (pipeline, 0, n_planes = cogl_multi_plane_texture_get_n_planes (stex->texture);
COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE); for (i = 0; i < n_planes; i++)
cogl_pipeline_set_layer_wrap_mode_s (pipeline, 1, {
COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE); cogl_pipeline_set_layer_wrap_mode_s (pipeline, i,
cogl_pipeline_set_layer_wrap_mode_t (pipeline, 1, COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE);
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); cogl_matrix_init_identity (&matrix);
@ -409,11 +417,24 @@ get_base_pipeline (MetaShapedTexture *stex,
0); 0);
} }
cogl_pipeline_set_layer_matrix (pipeline, 0, &matrix); for (i = 0; i < n_planes + 1; i++)
cogl_pipeline_set_layer_matrix (pipeline, 1, &matrix); cogl_pipeline_set_layer_matrix (pipeline, i, &matrix);
cogl_clear_object (&stex->pixel_format_conversion);
stex->pixel_format_conversion = cogl_pixel_format_conversion_new (format);
if (stex->pixel_format_conversion)
{
cogl_pixel_format_conversion_attach_to_pipeline (stex->pixel_format_conversion,
pipeline,
n_planes - 1);
}
if (stex->snippet) 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; stex->base_pipeline = pipeline;
@ -432,12 +453,14 @@ get_masked_pipeline (MetaShapedTexture *stex,
CoglContext *ctx) CoglContext *ctx)
{ {
CoglPipeline *pipeline; CoglPipeline *pipeline;
uint8_t n_planes;
if (stex->masked_pipeline) if (stex->masked_pipeline)
return stex->masked_pipeline; return stex->masked_pipeline;
pipeline = cogl_pipeline_copy (get_base_pipeline (stex, ctx)); pipeline = cogl_pipeline_copy (get_base_pipeline (stex, ctx));
cogl_pipeline_set_layer_combine (pipeline, 1, n_planes = cogl_multi_plane_texture_get_n_planes (stex->texture);
cogl_pipeline_set_layer_combine (pipeline, n_planes,
"RGBA = MODULATE (PREVIOUS, TEXTURE[A])", "RGBA = MODULATE (PREVIOUS, TEXTURE[A])",
NULL); NULL);
@ -451,17 +474,15 @@ get_unblended_pipeline (MetaShapedTexture *stex,
CoglContext *ctx) CoglContext *ctx)
{ {
CoglPipeline *pipeline; CoglPipeline *pipeline;
CoglColor color;
if (stex->unblended_pipeline) if (stex->unblended_pipeline)
return stex->unblended_pipeline; return stex->unblended_pipeline;
pipeline = cogl_pipeline_copy (get_base_pipeline (stex, ctx)); pipeline = cogl_pipeline_copy (get_base_pipeline (stex, ctx));
cogl_color_init_from_4ub (&color, 255, 255, 255, 255);
cogl_pipeline_set_blend (pipeline, cogl_pipeline_set_blend (pipeline,
"RGBA = ADD (SRC_COLOR, 0)", "RGBA = ADD (SRC_COLOR, 0)",
NULL); NULL);
cogl_pipeline_set_color (pipeline, &color); cogl_pipeline_set_color4ub (pipeline, 255, 255, 255, 255);
stex->unblended_pipeline = pipeline; stex->unblended_pipeline = pipeline;
@ -503,23 +524,21 @@ paint_clipped_rectangle (MetaShapedTexture *stex,
} }
static void static void
set_cogl_texture (MetaShapedTexture *stex, set_planar_texture (MetaShapedTexture *stex,
CoglTexture *cogl_tex) CoglMultiPlaneTexture *planar_tex)
{ {
int width, height; int width, height;
g_return_if_fail (META_IS_SHAPED_TEXTURE (stex)); g_return_if_fail (META_IS_SHAPED_TEXTURE (stex));
if (stex->texture) cogl_clear_object (&stex->texture);
cogl_object_unref (stex->texture); stex->texture = planar_tex;
stex->texture = cogl_tex; if (planar_tex != NULL)
if (cogl_tex != NULL)
{ {
cogl_object_ref (cogl_tex); cogl_object_ref (planar_tex);
width = cogl_texture_get_width (COGL_TEXTURE (cogl_tex)); width = cogl_multi_plane_texture_get_width (planar_tex);
height = cogl_texture_get_height (COGL_TEXTURE (cogl_tex)); height = cogl_multi_plane_texture_get_height (planar_tex);
} }
else else
{ {
@ -540,8 +559,11 @@ set_cogl_texture (MetaShapedTexture *stex,
* previous buffer. We only queue a redraw in response to surface * previous buffer. We only queue a redraw in response to surface
* damage. */ * damage. */
/* if (FALSE) */
if (stex->create_mipmaps) 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 static gboolean
@ -559,10 +581,10 @@ texture_is_idle_and_not_mipmapped (gpointer user_data)
} }
static void static void
do_paint (MetaShapedTexture *stex, do_paint (MetaShapedTexture *stex,
CoglFramebuffer *fb, CoglFramebuffer *fb,
CoglTexture *paint_tex, CoglMultiPlaneTexture *paint_tex,
cairo_region_t *clip_region) cairo_region_t *clip_region)
{ {
double tex_scale; double tex_scale;
int dst_width, dst_height; int dst_width, dst_height;
@ -575,8 +597,12 @@ do_paint (MetaShapedTexture *stex,
CoglContext *ctx; CoglContext *ctx;
ClutterActorBox alloc; ClutterActorBox alloc;
CoglPipelineFilter filter; CoglPipelineFilter filter;
uint8_t n_planes;
clutter_actor_get_scale (CLUTTER_ACTOR (stex), &tex_scale, NULL); 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); ensure_size_valid (stex);
dst_width = stex->dst_width; dst_width = stex->dst_width;
@ -682,8 +708,15 @@ do_paint (MetaShapedTexture *stex,
if (!cairo_region_is_empty (region)) if (!cairo_region_is_empty (region))
{ {
opaque_pipeline = get_unblended_pipeline (stex, ctx); 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); n_rects = cairo_region_num_rectangles (region);
for (i = 0; i < n_rects; i++) for (i = 0; i < n_rects; i++)
@ -714,6 +747,7 @@ do_paint (MetaShapedTexture *stex,
if (!blended_tex_region || !cairo_region_is_empty (blended_tex_region)) if (!blended_tex_region || !cairo_region_is_empty (blended_tex_region))
{ {
CoglPipeline *blended_pipeline; CoglPipeline *blended_pipeline;
guint i;
if (stex->mask_texture == NULL) if (stex->mask_texture == NULL)
{ {
@ -722,16 +756,20 @@ do_paint (MetaShapedTexture *stex,
else else
{ {
blended_pipeline = get_masked_pipeline (stex, ctx); blended_pipeline = get_masked_pipeline (stex, ctx);
cogl_pipeline_set_layer_texture (blended_pipeline, 1, stex->mask_texture); cogl_pipeline_set_layer_texture (blended_pipeline, n_planes, stex->mask_texture);
cogl_pipeline_set_layer_filters (blended_pipeline, 1, filter, filter); cogl_pipeline_set_layer_filters (blended_pipeline, n_planes, filter, filter);
} }
cogl_pipeline_set_layer_texture (blended_pipeline, 0, paint_tex); for (i = 0; i < n_planes; i++)
cogl_pipeline_set_layer_filters (blended_pipeline, 0, filter, filter); {
CoglTexture *plane = cogl_multi_plane_texture_get_plane (paint_tex, i);
CoglColor color; cogl_pipeline_set_layer_texture (blended_pipeline, i, plane);
cogl_color_init_from_4ub (&color, opacity, opacity, opacity, opacity); cogl_pipeline_set_layer_filters (blended_pipeline, i, filter, filter);
cogl_pipeline_set_color (blended_pipeline, &color); }
cogl_pipeline_set_color4ub (blended_pipeline,
opacity, opacity, opacity, opacity);
if (blended_tex_region) if (blended_tex_region)
{ {
@ -773,7 +811,7 @@ static void
meta_shaped_texture_paint (ClutterActor *actor) meta_shaped_texture_paint (ClutterActor *actor)
{ {
MetaShapedTexture *stex = META_SHAPED_TEXTURE (actor); MetaShapedTexture *stex = META_SHAPED_TEXTURE (actor);
CoglTexture *paint_tex; CoglMultiPlaneTexture *paint_tex;
CoglFramebuffer *fb; CoglFramebuffer *fb;
if (!stex->texture) if (!stex->texture)
@ -828,11 +866,11 @@ meta_shaped_texture_paint (ClutterActor *actor)
} }
else else
{ {
paint_tex = COGL_TEXTURE (stex->texture); paint_tex = stex->texture;
} }
if (cogl_texture_get_width (paint_tex) == 0 || if (cogl_multi_plane_texture_get_width (paint_tex) == 0 ||
cogl_texture_get_height (paint_tex) == 0) cogl_multi_plane_texture_get_height (paint_tex) == 0)
return; return;
fb = cogl_get_draw_framebuffer (); fb = cogl_get_draw_framebuffer ();
@ -906,7 +944,7 @@ meta_shaped_texture_set_create_mipmaps (MetaShapedTexture *stex,
if (create_mipmaps != stex->create_mipmaps) if (create_mipmaps != stex->create_mipmaps)
{ {
CoglTexture *base_texture; CoglMultiPlaneTexture *base_texture;
stex->create_mipmaps = create_mipmaps; stex->create_mipmaps = create_mipmaps;
base_texture = create_mipmaps ? stex->texture : NULL; base_texture = create_mipmaps ? stex->texture : NULL;
meta_texture_tower_set_base_texture (stex->paint_tower, base_texture); meta_texture_tower_set_base_texture (stex->paint_tower, base_texture);
@ -1089,15 +1127,15 @@ meta_shaped_texture_update_area (MetaShapedTexture *stex,
/** /**
* meta_shaped_texture_set_texture: * meta_shaped_texture_set_texture:
* @stex: The #MetaShapedTexture * @stex: The #MetaShapedTexture
* @pixmap: The #CoglTexture to display * @pixmap: The #CoglMultiPlaneTexture to display
*/ */
void void
meta_shaped_texture_set_texture (MetaShapedTexture *stex, meta_shaped_texture_set_texture (MetaShapedTexture *stex,
CoglTexture *texture) CoglMultiPlaneTexture *texture)
{ {
g_return_if_fail (META_IS_SHAPED_TEXTURE (stex)); g_return_if_fail (META_IS_SHAPED_TEXTURE (stex));
set_cogl_texture (stex, texture); set_planar_texture (stex, texture);
} }
/** /**
@ -1127,7 +1165,7 @@ meta_shaped_texture_set_snippet (MetaShapedTexture *stex,
meta_shaped_texture_reset_pipelines (stex); meta_shaped_texture_reset_pipelines (stex);
g_clear_pointer (&stex->snippet, cogl_object_unref); cogl_clear_object (&stex->snippet);
if (snippet) if (snippet)
stex->snippet = cogl_object_ref (snippet); stex->snippet = cogl_object_ref (snippet);
} }
@ -1138,11 +1176,12 @@ meta_shaped_texture_set_snippet (MetaShapedTexture *stex,
* *
* Returns: (transfer none): the unshaped texture * Returns: (transfer none): the unshaped texture
*/ */
CoglTexture * CoglMultiPlaneTexture *
meta_shaped_texture_get_texture (MetaShapedTexture *stex) meta_shaped_texture_get_texture (MetaShapedTexture *stex)
{ {
g_return_val_if_fail (META_IS_SHAPED_TEXTURE (stex), NULL); g_return_val_if_fail (META_IS_SHAPED_TEXTURE (stex), NULL);
return COGL_TEXTURE (stex->texture);
return stex->texture;
} }
/** /**
@ -1247,7 +1286,15 @@ meta_shaped_texture_reset_viewport_dst_size (MetaShapedTexture *stex)
static gboolean static gboolean
should_get_via_offscreen (MetaShapedTexture *stex) 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; return TRUE;
if (stex->has_viewport_src_rect || stex->has_viewport_dst_size) if (stex->has_viewport_src_rect || stex->has_viewport_dst_size)
@ -1364,19 +1411,19 @@ get_image_via_offscreen (MetaShapedTexture *stex,
* Returns: (transfer full): a new cairo surface to be freed with * Returns: (transfer full): a new cairo surface to be freed with
* cairo_surface_destroy(). * cairo_surface_destroy().
*/ */
/* XXX Still need to fix this, but apparently only used for screenshot */
cairo_surface_t * cairo_surface_t *
meta_shaped_texture_get_image (MetaShapedTexture *stex, meta_shaped_texture_get_image (MetaShapedTexture *stex,
cairo_rectangle_int_t *clip) cairo_rectangle_int_t *clip)
{ {
cairo_rectangle_int_t *transformed_clip = NULL; cairo_rectangle_int_t *transformed_clip = NULL;
CoglTexture *texture, *mask_texture; CoglTexture *texture;
CoglTexture *mask_texture;
cairo_surface_t *surface; cairo_surface_t *surface;
g_return_val_if_fail (META_IS_SHAPED_TEXTURE (stex), NULL); g_return_val_if_fail (META_IS_SHAPED_TEXTURE (stex), NULL);
texture = COGL_TEXTURE (stex->texture); if (stex->texture == NULL)
if (texture == NULL)
return NULL; return NULL;
ensure_size_valid (stex); ensure_size_valid (stex);
@ -1409,6 +1456,9 @@ meta_shaped_texture_get_image (MetaShapedTexture *stex,
if (should_get_via_offscreen (stex)) if (should_get_via_offscreen (stex))
return get_image_via_offscreen (stex, transformed_clip); 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) if (transformed_clip)
texture = cogl_texture_new_from_sub_texture (texture, texture = cogl_texture_new_from_sub_texture (texture,
transformed_clip->x, transformed_clip->x,

View File

@ -45,7 +45,7 @@ struct _MetaSurfaceActorX11
MetaDisplay *display; MetaDisplay *display;
CoglTexture *texture; CoglMultiPlaneTexture *texture;
Pixmap pixmap; Pixmap pixmap;
Damage damage; 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)))) 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"); g_warning ("NOTE: Not using GLX TFP!\n");
self->texture = texture; self->texture = cogl_multi_plane_texture_new_single_plane (_cogl_texture_get_format (texture),
meta_shaped_texture_set_texture (stex, texture); texture);
meta_shaped_texture_set_texture (stex, self->texture);
} }
static void static void
@ -187,6 +188,7 @@ meta_surface_actor_x11_process_damage (MetaSurfaceActor *actor,
int x, int y, int width, int height) int x, int y, int width, int height)
{ {
MetaSurfaceActorX11 *self = META_SURFACE_ACTOR_X11 (actor); MetaSurfaceActorX11 *self = META_SURFACE_ACTOR_X11 (actor);
CoglTexture *texture;
self->received_damage = TRUE; self->received_damage = TRUE;
@ -210,7 +212,8 @@ meta_surface_actor_x11_process_damage (MetaSurfaceActor *actor,
if (!is_visible (self)) if (!is_visible (self))
return; 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); x, y, width, height);
} }

View File

@ -325,7 +325,8 @@ gboolean
meta_surface_actor_is_argb32 (MetaSurfaceActor *self) meta_surface_actor_is_argb32 (MetaSurfaceActor *self)
{ {
MetaShapedTexture *stex = meta_surface_actor_get_texture (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 /* If we don't have a texture, like during initialization, assume
* that we're ARGB32. * that we're ARGB32.
@ -335,9 +336,14 @@ meta_surface_actor_is_argb32 (MetaSurfaceActor *self)
* place. This prevents us from continually redirecting and * place. This prevents us from continually redirecting and
* unredirecting on every paint. * unredirecting on every paint.
*/ */
if (!texture) if (!mtex)
return !meta_surface_actor_is_unredirected (self); 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)) switch (cogl_texture_get_components (texture))
{ {
case COGL_TEXTURE_COMPONENTS_A: case COGL_TEXTURE_COMPONENTS_A:

View File

@ -58,8 +58,8 @@ typedef struct
struct _MetaTextureTower struct _MetaTextureTower
{ {
int n_levels; int n_levels;
CoglTexture *textures[MAX_TEXTURE_LEVELS]; CoglMultiPlaneTexture *textures[MAX_TEXTURE_LEVELS];
CoglOffscreen *fbos[MAX_TEXTURE_LEVELS]; GList *fbos[MAX_TEXTURE_LEVELS];
Box invalid[MAX_TEXTURE_LEVELS]; Box invalid[MAX_TEXTURE_LEVELS];
CoglPipeline *pipeline_template; CoglPipeline *pipeline_template;
}; };
@ -112,8 +112,8 @@ meta_texture_tower_free (MetaTextureTower *tower)
* unset or until the tower is freed. * unset or until the tower is freed.
*/ */
void void
meta_texture_tower_set_base_texture (MetaTextureTower *tower, meta_texture_tower_set_base_texture (MetaTextureTower *tower,
CoglTexture *texture) CoglMultiPlaneTexture *texture)
{ {
int i; int i;
@ -126,22 +126,14 @@ meta_texture_tower_set_base_texture (MetaTextureTower *tower,
{ {
for (i = 1; i < tower->n_levels; i++) for (i = 1; i < tower->n_levels; i++)
{ {
if (tower->textures[i] != NULL) cogl_clear_object (&tower->textures[i]);
{
cogl_object_unref (tower->textures[i]);
tower->textures[i] = NULL;
}
if (tower->fbos[i] != NULL) g_list_free_full (tower->fbos[i], cogl_object_unref);
{ tower->fbos[i] = NULL;
cogl_object_unref (tower->fbos[i]);
tower->fbos[i] = NULL;
}
} }
cogl_object_unref (tower->textures[0]);
} }
cogl_clear_object (&tower->textures[0]);
tower->textures[0] = texture; tower->textures[0] = texture;
if (tower->textures[0] != NULL) if (tower->textures[0] != NULL)
@ -150,8 +142,8 @@ meta_texture_tower_set_base_texture (MetaTextureTower *tower,
cogl_object_ref (tower->textures[0]); cogl_object_ref (tower->textures[0]);
width = cogl_texture_get_width (tower->textures[0]); width = cogl_multi_plane_texture_get_width (tower->textures[0]);
height = cogl_texture_get_height (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 = 1 + MAX ((int)(M_LOG2E * log (width)), (int)(M_LOG2E * log (height)));
tower->n_levels = MIN(tower->n_levels, MAX_TEXTURE_LEVELS); 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) if (tower->textures[0] == NULL)
return; return;
texture_width = cogl_texture_get_width (tower->textures[0]); texture_width = cogl_multi_plane_texture_get_width (tower->textures[0]);
texture_height = cogl_texture_get_height (tower->textures[0]); texture_height = cogl_multi_plane_texture_get_height (tower->textures[0]);
invalid.x1 = x; invalid.x1 = x;
invalid.y1 = y; invalid.y1 = y;
@ -351,9 +343,27 @@ texture_tower_create_texture (MetaTextureTower *tower,
int width, int width,
int height) int height)
{ {
tower->textures[level] = cogl_texture_new_with_size (width, height, CoglMultiPlaneTexture *base_tex = tower->textures[0];
COGL_TEXTURE_NO_AUTO_MIPMAP, GPtrArray *planes;
TEXTURE_FORMAT); uint8_t i, n_planes;
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++)
{
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].x1 = 0;
tower->invalid[level].y1 = 0; tower->invalid[level].y1 = 0;
@ -365,51 +375,69 @@ static void
texture_tower_revalidate (MetaTextureTower *tower, texture_tower_revalidate (MetaTextureTower *tower,
int level) int level)
{ {
CoglTexture *source_texture = tower->textures[level - 1]; CoglMultiPlaneTexture *src_tex = tower->textures[level - 1];
int source_texture_width = cogl_texture_get_width (source_texture); int src_width = cogl_multi_plane_texture_get_width (src_tex);
int source_texture_height = cogl_texture_get_height (source_texture); int src_height = cogl_multi_plane_texture_get_height (src_tex);
CoglTexture *dest_texture = tower->textures[level]; uint8_t src_tex_n_planes = cogl_multi_plane_texture_get_n_planes (src_tex);
int dest_texture_width = cogl_texture_get_width (dest_texture); CoglMultiPlaneTexture *dest_tex = tower->textures[level];
int dest_texture_height = cogl_texture_get_height (dest_texture); int dest_width = cogl_multi_plane_texture_get_width (dest_tex);
Box *invalid = &tower->invalid[level]; int dest_height = cogl_multi_plane_texture_get_height (dest_tex);
CoglFramebuffer *fb; uint8_t i;
GError *catch_error = NULL;
CoglPipeline *pipeline;
if (tower->fbos[level] == NULL)
tower->fbos[level] = cogl_offscreen_new_with_texture (dest_texture);
fb = COGL_FRAMEBUFFER (tower->fbos[level]); /* FIXME: cogl_offscreen_texture_new_with_texture doesn't work for
* multi-plane textures, so we have to make an FBO for each layer */
if (!cogl_framebuffer_allocate (fb, &catch_error)) for (i = 0; i < src_tex_n_planes; i++)
{ {
g_error_free (catch_error); Box *invalid = &tower->invalid[level];
return; CoglTexture *src_plane, *dest_plane;
CoglFramebuffer *fb;
GError *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))
{
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].x1 = tower->invalid[level].x2 = 0;
tower->invalid[level].y1 = tower->invalid[level].y2 = 0; tower->invalid[level].y1 = tower->invalid[level].y2 = 0;
} }
@ -427,7 +455,7 @@ texture_tower_revalidate (MetaTextureTower *tower,
* Return value: the COGL texture handle to use for painting, or * Return value: the COGL texture handle to use for painting, or
* %NULL if no base texture has yet been set. * %NULL if no base texture has yet been set.
*/ */
CoglTexture * CoglMultiPlaneTexture *
meta_texture_tower_get_paint_texture (MetaTextureTower *tower) meta_texture_tower_get_paint_texture (MetaTextureTower *tower)
{ {
int texture_width, texture_height; int texture_width, texture_height;
@ -438,8 +466,8 @@ meta_texture_tower_get_paint_texture (MetaTextureTower *tower)
if (tower->textures[0] == NULL) if (tower->textures[0] == NULL)
return NULL; return NULL;
texture_width = cogl_texture_get_width (tower->textures[0]); texture_width = cogl_multi_plane_texture_get_width (tower->textures[0]);
texture_height = cogl_texture_get_height (tower->textures[0]); texture_height = cogl_multi_plane_texture_get_height (tower->textures[0]);
level = get_paint_level(texture_width, texture_height); level = get_paint_level(texture_width, texture_height);
if (level < 0) /* singular paint matrix, scaled to nothing */ if (level < 0) /* singular paint matrix, scaled to nothing */

View File

@ -53,14 +53,14 @@ typedef struct _MetaTextureTower MetaTextureTower;
MetaTextureTower *meta_texture_tower_new (void); MetaTextureTower *meta_texture_tower_new (void);
void meta_texture_tower_free (MetaTextureTower *tower); void meta_texture_tower_free (MetaTextureTower *tower);
void meta_texture_tower_set_base_texture (MetaTextureTower *tower, void meta_texture_tower_set_base_texture (MetaTextureTower *tower,
CoglTexture *texture); CoglMultiPlaneTexture *texture);
void meta_texture_tower_update_area (MetaTextureTower *tower, void meta_texture_tower_update_area (MetaTextureTower *tower,
int x, int x,
int y, int y,
int width, int width,
int height); int height);
CoglTexture *meta_texture_tower_get_paint_texture (MetaTextureTower *tower); CoglMultiPlaneTexture *meta_texture_tower_get_paint_texture (MetaTextureTower *tower);
G_END_DECLS G_END_DECLS

View File

@ -1502,7 +1502,8 @@ build_and_scan_frame_mask (MetaWindowActor *self,
guchar *mask_data; guchar *mask_data;
guint tex_width, tex_height; guint tex_width, tex_height;
MetaShapedTexture *stex; MetaShapedTexture *stex;
CoglTexture *paint_tex, *mask_texture; CoglMultiPlaneTexture *paint_tex;
CoglTexture *mask_texture;
int stride; int stride;
cairo_t *cr; cairo_t *cr;
cairo_surface_t *surface; cairo_surface_t *surface;
@ -1517,8 +1518,8 @@ build_and_scan_frame_mask (MetaWindowActor *self,
if (paint_tex == NULL) if (paint_tex == NULL)
return; return;
tex_width = cogl_texture_get_width (paint_tex); tex_width = cogl_multi_plane_texture_get_width (paint_tex);
tex_height = cogl_texture_get_height (paint_tex); tex_height = cogl_multi_plane_texture_get_height (paint_tex);
stride = cairo_format_stride_for_width (CAIRO_FORMAT_A8, tex_width); stride = cairo_format_stride_for_width (CAIRO_FORMAT_A8, tex_width);

View File

@ -52,7 +52,7 @@ gboolean meta_shaped_texture_update_area (MetaShapedTexture *stex,
int height); int height);
META_EXPORT META_EXPORT
CoglTexture * meta_shaped_texture_get_texture (MetaShapedTexture *stex); CoglMultiPlaneTexture * meta_shaped_texture_get_texture (MetaShapedTexture *stex);
META_EXPORT META_EXPORT
void meta_shaped_texture_set_mask_texture (MetaShapedTexture *stex, void meta_shaped_texture_set_mask_texture (MetaShapedTexture *stex,

View File

@ -123,7 +123,7 @@ meta_wayland_buffer_realize (MetaWaylandBuffer *buffer)
stream = meta_wayland_egl_stream_new (buffer, NULL); stream = meta_wayland_egl_stream_new (buffer, NULL);
if (stream) if (stream)
{ {
CoglTexture2D *texture; CoglMultiPlaneTexture *texture;
texture = meta_wayland_egl_stream_create_texture (stream, NULL); texture = meta_wayland_egl_stream_create_texture (stream, NULL);
if (!texture) if (!texture)
@ -131,7 +131,7 @@ meta_wayland_buffer_realize (MetaWaylandBuffer *buffer)
buffer->egl_stream.stream = stream; buffer->egl_stream.stream = stream;
buffer->type = META_WAYLAND_BUFFER_TYPE_EGL_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); buffer->is_y_inverted = meta_wayland_egl_stream_is_y_inverted (stream);
return TRUE; return TRUE;
@ -163,43 +163,78 @@ shm_buffer_get_cogl_pixel_format (struct wl_shm_buffer *shm_buffer,
CoglTextureComponents *components_out) CoglTextureComponents *components_out)
{ {
CoglPixelFormat format; CoglPixelFormat format;
CoglTextureComponents components = COGL_TEXTURE_COMPONENTS_RGBA;
switch (wl_shm_buffer_get_format (shm_buffer)) switch (wl_shm_buffer_get_format (shm_buffer))
{ {
#if G_BYTE_ORDER == G_BIG_ENDIAN #if G_BYTE_ORDER == G_BIG_ENDIAN
case WL_SHM_FORMAT_ARGB8888: case WL_SHM_FORMAT_ARGB8888:
format = COGL_PIXEL_FORMAT_ARGB_8888_PRE; format = COGL_PIXEL_FORMAT_ARGB_8888_PRE;
components_out[0] = COGL_TEXTURE_COMPONENTS_RGBA;
break; break;
case WL_SHM_FORMAT_XRGB8888: case WL_SHM_FORMAT_XRGB8888:
format = COGL_PIXEL_FORMAT_ARGB_8888; format = COGL_PIXEL_FORMAT_ARGB_8888;
components = COGL_TEXTURE_COMPONENTS_RGB; components_out[0] = COGL_TEXTURE_COMPONENTS_RGB;
break; break;
#elif G_BYTE_ORDER == G_LITTLE_ENDIAN #elif G_BYTE_ORDER == G_LITTLE_ENDIAN
case WL_SHM_FORMAT_ARGB8888: case WL_SHM_FORMAT_ARGB8888:
format = COGL_PIXEL_FORMAT_BGRA_8888_PRE; format = COGL_PIXEL_FORMAT_BGRA_8888_PRE;
components_out[0] = COGL_TEXTURE_COMPONENTS_RGBA;
break; break;
case WL_SHM_FORMAT_XRGB8888: case WL_SHM_FORMAT_XRGB8888:
format = COGL_PIXEL_FORMAT_BGRA_8888; format = COGL_PIXEL_FORMAT_BGRA_8888;
components = COGL_TEXTURE_COMPONENTS_RGB; components_out[0] = COGL_TEXTURE_COMPONENTS_RGB;
break; break;
#endif #endif
case WL_SHM_FORMAT_NV12:
format = COGL_PIXEL_FORMAT_NV12;
components_out[0] = COGL_TEXTURE_COMPONENTS_R;
components_out[1] = COGL_TEXTURE_COMPONENTS_RG;
break;
case WL_SHM_FORMAT_NV21:
format = COGL_PIXEL_FORMAT_NV21;
components_out[0] = COGL_TEXTURE_COMPONENTS_R;
components_out[1] = COGL_TEXTURE_COMPONENTS_RG;
break;
case WL_SHM_FORMAT_YUV422:
format = COGL_PIXEL_FORMAT_YUV422;
components_out[0] = COGL_TEXTURE_COMPONENTS_R;
components_out[1] = COGL_TEXTURE_COMPONENTS_R;
components_out[2] = COGL_TEXTURE_COMPONENTS_R;
break;
case WL_SHM_FORMAT_YVU422:
format = COGL_PIXEL_FORMAT_YVU422;
components_out[0] = COGL_TEXTURE_COMPONENTS_R;
components_out[1] = COGL_TEXTURE_COMPONENTS_R;
components_out[2] = COGL_TEXTURE_COMPONENTS_R;
break;
case WL_SHM_FORMAT_YUV444:
format = COGL_PIXEL_FORMAT_YUV444;
components_out[0] = COGL_TEXTURE_COMPONENTS_R;
components_out[1] = COGL_TEXTURE_COMPONENTS_R;
components_out[2] = COGL_TEXTURE_COMPONENTS_R;
break;
case WL_SHM_FORMAT_YVU444:
format = COGL_PIXEL_FORMAT_YVU444;
components_out[0] = COGL_TEXTURE_COMPONENTS_R;
components_out[1] = COGL_TEXTURE_COMPONENTS_R;
components_out[2] = COGL_TEXTURE_COMPONENTS_R;
break;
default: default:
g_warn_if_reached (); g_warn_if_reached ();
format = COGL_PIXEL_FORMAT_ARGB_8888; format = COGL_PIXEL_FORMAT_ARGB_8888;
components_out[0] = COGL_TEXTURE_COMPONENTS_RGBA;
} }
if (format_out) if (format_out)
*format_out = format; *format_out = format;
if (components_out)
*components_out = components;
} }
static gboolean static gboolean
shm_buffer_attach (MetaWaylandBuffer *buffer, shm_buffer_attach (MetaWaylandBuffer *buffer,
CoglTexture **texture, CoglMultiPlaneTexture **texture,
gboolean *changed_texture, gboolean *changed_texture,
GError **error) GError **error)
{ {
MetaBackend *backend = meta_get_backend (); MetaBackend *backend = meta_get_backend ();
ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend); ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
@ -207,21 +242,30 @@ shm_buffer_attach (MetaWaylandBuffer *buffer,
struct wl_shm_buffer *shm_buffer; struct wl_shm_buffer *shm_buffer;
int stride, width, height; int stride, width, height;
CoglPixelFormat format; CoglPixelFormat format;
CoglTextureComponents components; CoglTextureComponents components[3];
CoglBitmap *bitmap; guint i, n_planes;
CoglTexture *new_texture; uint8_t h_factors[3], v_factors[3], bpp[3];
CoglPixelFormat subformats[3];
gsize plane_offset = 0;
guint8 *data;
GPtrArray *planes;
/* Query the necessary parameters */
shm_buffer = wl_shm_buffer_get (buffer->resource); shm_buffer = wl_shm_buffer_get (buffer->resource);
stride = wl_shm_buffer_get_stride (shm_buffer); stride = wl_shm_buffer_get_stride (shm_buffer);
width = wl_shm_buffer_get_width (shm_buffer); width = wl_shm_buffer_get_width (shm_buffer);
height = wl_shm_buffer_get_height (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);
cogl_pixel_format_get_subformats (format, subformats);
cogl_pixel_format_get_bytes_per_pixel (format, bpp);
if (*texture && if (*texture &&
cogl_texture_get_width (*texture) == width && cogl_multi_plane_texture_get_width (*texture) == width &&
cogl_texture_get_height (*texture) == height && cogl_multi_plane_texture_get_height (*texture) == height &&
cogl_texture_get_components (*texture) == components && /*XXX cogl_texture_get_components (*texture) == components && */
_cogl_texture_get_format (*texture) == format) cogl_multi_plane_texture_get_format (*texture) == format)
{ {
buffer->is_y_inverted = TRUE; buffer->is_y_inverted = TRUE;
*changed_texture = FALSE; *changed_texture = FALSE;
@ -230,56 +274,92 @@ shm_buffer_attach (MetaWaylandBuffer *buffer,
cogl_clear_object (texture); cogl_clear_object (texture);
/* Safely access the data inside the buffer */
wl_shm_buffer_begin_access (shm_buffer); wl_shm_buffer_begin_access (shm_buffer);
data = wl_shm_buffer_get_data (shm_buffer);
bitmap = cogl_bitmap_new_for_data (cogl_context, planes = g_ptr_array_new_full (n_planes, cogl_object_unref);
width, height, for (i = 0; i < n_planes; i++)
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))
{ {
g_clear_pointer (&new_texture, cogl_object_unref); int plane_stride;
if (g_error_matches (*error, COGL_TEXTURE_ERROR, COGL_TEXTURE_ERROR_SIZE)) 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);
g_assert (plane_bitmap);
/* 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; 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); g_clear_error (error);
texture_sliced = texture_sliced =
cogl_texture_2d_sliced_new_from_bitmap (bitmap, cogl_texture_2d_sliced_new_from_bitmap (plane_bitmap,
COGL_TEXTURE_MAX_WASTE); COGL_TEXTURE_MAX_WASTE);
new_texture = COGL_TEXTURE (texture_sliced); plane_texture = COGL_TEXTURE (texture_sliced);
cogl_texture_set_components (new_texture, components);
if (!cogl_texture_allocate (new_texture, error)) cogl_texture_set_components (plane_texture, components[i]);
g_clear_pointer (&new_texture, cogl_object_unref);
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 = cogl_multi_plane_texture_new (format,
(CoglTexture **) g_ptr_array_free (planes, FALSE),
n_planes);
wl_shm_buffer_end_access (shm_buffer); wl_shm_buffer_end_access (shm_buffer);
if (!new_texture)
return FALSE;
*texture = new_texture;
*changed_texture = TRUE; *changed_texture = TRUE;
buffer->is_y_inverted = TRUE; buffer->is_y_inverted = TRUE;
return TRUE; return TRUE;
failure:
*texture = NULL;
return FALSE;
} }
static gboolean static gboolean
egl_image_buffer_attach (MetaWaylandBuffer *buffer, egl_image_buffer_attach (MetaWaylandBuffer *buffer,
CoglTexture **texture, CoglMultiPlaneTexture **texture,
gboolean *changed_texture, gboolean *changed_texture,
GError **error) GError **error)
{ {
MetaBackend *backend = meta_get_backend (); MetaBackend *backend = meta_get_backend ();
MetaEgl *egl = meta_backend_get_egl (backend); MetaEgl *egl = meta_backend_get_egl (backend);
@ -288,8 +368,9 @@ egl_image_buffer_attach (MetaWaylandBuffer *buffer,
EGLDisplay egl_display = cogl_egl_context_get_egl_display (cogl_context); EGLDisplay egl_display = cogl_egl_context_get_egl_display (cogl_context);
int format, width, height, y_inverted; int format, width, height, y_inverted;
CoglPixelFormat cogl_format; CoglPixelFormat cogl_format;
EGLImageKHR egl_image; CoglTextureComponents components[3];
CoglTexture2D *texture_2d; guint i, n_planes;
GPtrArray *planes;
if (buffer->egl_image.texture) if (buffer->egl_image.texture)
{ {
@ -299,6 +380,7 @@ egl_image_buffer_attach (MetaWaylandBuffer *buffer,
return TRUE; return TRUE;
} }
/* Query the necessary properties */
if (!meta_egl_query_wayland_buffer (egl, egl_display, buffer->resource, if (!meta_egl_query_wayland_buffer (egl, egl_display, buffer->resource,
EGL_TEXTURE_FORMAT, &format, EGL_TEXTURE_FORMAT, &format,
error)) error))
@ -319,6 +401,7 @@ egl_image_buffer_attach (MetaWaylandBuffer *buffer,
NULL)) NULL))
y_inverted = EGL_TRUE; y_inverted = EGL_TRUE;
/* Map the EGL texture format to CoglPixelFormat, if possible */
switch (format) switch (format)
{ {
case EGL_TEXTURE_RGB: case EGL_TEXTURE_RGB:
@ -327,6 +410,12 @@ egl_image_buffer_attach (MetaWaylandBuffer *buffer,
case EGL_TEXTURE_RGBA: case EGL_TEXTURE_RGBA:
cogl_format = COGL_PIXEL_FORMAT_RGBA_8888_PRE; cogl_format = COGL_PIXEL_FORMAT_RGBA_8888_PRE;
break; break;
case EGL_TEXTURE_Y_UV_WL:
cogl_format = COGL_PIXEL_FORMAT_NV12;
break;
case EGL_TEXTURE_Y_U_V_WL:
cogl_format = COGL_PIXEL_FORMAT_YUV444;
break;
default: default:
g_set_error (error, G_IO_ERROR, g_set_error (error, G_IO_ERROR,
G_IO_ERROR_FAILED, G_IO_ERROR_FAILED,
@ -334,27 +423,51 @@ egl_image_buffer_attach (MetaWaylandBuffer *buffer,
return FALSE; return FALSE;
} }
/* The WL_bind_wayland_display spec states that EGL_NO_CONTEXT is to be used n_planes = cogl_pixel_format_get_n_planes (cogl_format);
* in conjunction with the EGL_WAYLAND_BUFFER_WL target. */ cogl_pixel_format_get_cogl_components (cogl_format, components);
egl_image = meta_egl_create_image (egl, egl_display, EGL_NO_CONTEXT, planes = g_ptr_array_new_full (n_planes, cogl_object_unref);
EGL_WAYLAND_BUFFER_WL, buffer->resource,
NULL,
error);
if (egl_image == EGL_NO_IMAGE_KHR)
return FALSE;
texture_2d = cogl_egl_texture_2d_new_from_image (cogl_context, /* Each EGLImage is a plane in the final texture */
width, height, for (i = 0; i < n_planes; i++)
cogl_format, {
egl_image, EGLint egl_attribs[3];
error); 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) /* The WL_bind_wayland_display spec states that EGL_NO_CONTEXT is to be
return FALSE; * 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,
components[i],
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; buffer->is_y_inverted = !!y_inverted;
cogl_clear_object (texture); cogl_clear_object (texture);
@ -362,14 +475,19 @@ egl_image_buffer_attach (MetaWaylandBuffer *buffer,
*changed_texture = TRUE; *changed_texture = TRUE;
return TRUE; return TRUE;
on_error:
g_ptr_array_free (planes, TRUE);
return FALSE;
} }
#ifdef HAVE_WAYLAND_EGLSTREAM #ifdef HAVE_WAYLAND_EGLSTREAM
static gboolean static gboolean
egl_stream_buffer_attach (MetaWaylandBuffer *buffer, egl_stream_buffer_attach (MetaWaylandBuffer *buffer,
CoglTexture **texture, CoglMultiPlaneTexture **texture,
gboolean *changed_texture, gboolean *changed_texture,
GError **error) GError **error)
{ {
MetaWaylandEglStream *stream = buffer->egl_stream.stream; MetaWaylandEglStream *stream = buffer->egl_stream.stream;
@ -406,10 +524,10 @@ egl_stream_buffer_attach (MetaWaylandBuffer *buffer,
* meta_wayland_buffer_attach(), which also might free it, as described above. * meta_wayland_buffer_attach(), which also might free it, as described above.
*/ */
gboolean gboolean
meta_wayland_buffer_attach (MetaWaylandBuffer *buffer, meta_wayland_buffer_attach (MetaWaylandBuffer *buffer,
CoglTexture **texture, CoglMultiPlaneTexture **texture,
gboolean *changed_texture, gboolean *changed_texture,
GError **error) GError **error)
{ {
g_return_val_if_fail (buffer->resource, FALSE); g_return_val_if_fail (buffer->resource, FALSE);
@ -466,55 +584,94 @@ meta_wayland_buffer_is_y_inverted (MetaWaylandBuffer *buffer)
} }
static gboolean static gboolean
process_shm_buffer_damage (MetaWaylandBuffer *buffer, process_shm_buffer_damage (MetaWaylandBuffer *buffer,
CoglTexture *texture, CoglMultiPlaneTexture *texture,
cairo_region_t *region, cairo_region_t *region,
GError **error) GError **error)
{ {
struct wl_shm_buffer *shm_buffer; struct wl_shm_buffer *shm_buffer;
int i, n_rectangles;
gboolean set_texture_failed = FALSE; gboolean set_texture_failed = FALSE;
CoglPixelFormat format;
CoglTextureComponents components[3];
uint8_t h_factors[3], v_factors[3], bpp[3];
CoglPixelFormat subformats[3];
gsize plane_offset = 0;
const uint8_t *data;
int32_t stride, height;
uint8_t i, n_planes;
int j, n_rectangles;
n_rectangles = cairo_region_num_rectangles (region); n_rectangles = cairo_region_num_rectangles (region);
shm_buffer = wl_shm_buffer_get (buffer->resource); shm_buffer = wl_shm_buffer_get (buffer->resource);
/* Get the data */
wl_shm_buffer_begin_access (shm_buffer); 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_cogl_pixel_format (shm_buffer, &format, components);
/* Fetch some properties from the pixel format */
n_planes = cogl_multi_plane_texture_get_n_planes (texture);
cogl_pixel_format_get_subformats (format, subformats);
cogl_pixel_format_get_subsampling_factors (format, h_factors, v_factors);
cogl_pixel_format_get_bytes_per_pixel (format, bpp);
for (i = 0; i < n_planes; i++)
{ {
const uint8_t *data = wl_shm_buffer_get_data (shm_buffer); CoglTexture *plane;
int32_t stride = wl_shm_buffer_get_stride (shm_buffer); int plane_stride;
CoglPixelFormat format;
int bpp;
cairo_rectangle_int_t rect;
shm_buffer_get_cogl_pixel_format (shm_buffer, &format, NULL); plane = cogl_multi_plane_texture_get_plane (texture, i);
bpp = cogl_pixel_format_get_bytes_per_pixel_simple (format); plane_stride = (stride / bpp[0]) * bpp[i] / h_factors[i];
cairo_region_get_rectangle (region, i, &rect);
if (!_cogl_texture_set_region (texture, for (j = 0; j < n_rectangles; j++)
rect.width, rect.height,
format,
stride,
data + rect.x * bpp + rect.y * stride,
rect.x, rect.y,
0,
error))
{ {
set_texture_failed = TRUE; cairo_rectangle_int_t rect;
break; 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); wl_shm_buffer_end_access (shm_buffer);
return !set_texture_failed; return !set_texture_failed;
} }
void void
meta_wayland_buffer_process_damage (MetaWaylandBuffer *buffer, meta_wayland_buffer_process_damage (MetaWaylandBuffer *buffer,
CoglTexture *texture, CoglMultiPlaneTexture *texture,
cairo_region_t *region) cairo_region_t *region)
{ {
gboolean res = FALSE; gboolean res = FALSE;
GError *error = NULL; GError *error = NULL;

View File

@ -56,19 +56,19 @@ struct _MetaWaylandBuffer
MetaWaylandBufferType type; MetaWaylandBufferType type;
struct { struct {
CoglTexture *texture; CoglMultiPlaneTexture *texture;
} egl_image; } egl_image;
#ifdef HAVE_WAYLAND_EGLSTREAM #ifdef HAVE_WAYLAND_EGLSTREAM
struct { struct {
MetaWaylandEglStream *stream; MetaWaylandEglStream *stream;
CoglTexture *texture; CoglMultiPlaneTexture *texture;
} egl_stream; } egl_stream;
#endif #endif
struct { struct {
MetaWaylandDmaBufBuffer *dma_buf; MetaWaylandDmaBufBuffer *dma_buf;
CoglTexture *texture; CoglMultiPlaneTexture *texture;
} dma_buf; } 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); struct wl_resource * meta_wayland_buffer_get_resource (MetaWaylandBuffer *buffer);
gboolean meta_wayland_buffer_is_realized (MetaWaylandBuffer *buffer); gboolean meta_wayland_buffer_is_realized (MetaWaylandBuffer *buffer);
gboolean meta_wayland_buffer_realize (MetaWaylandBuffer *buffer); gboolean meta_wayland_buffer_realize (MetaWaylandBuffer *buffer);
gboolean meta_wayland_buffer_attach (MetaWaylandBuffer *buffer, gboolean meta_wayland_buffer_attach (MetaWaylandBuffer *buffer,
CoglTexture **texture, CoglMultiPlaneTexture **texture,
gboolean *changed_texture, gboolean *changed_texture,
GError **error); GError **error);
CoglSnippet * meta_wayland_buffer_create_snippet (MetaWaylandBuffer *buffer); CoglSnippet * meta_wayland_buffer_create_snippet (MetaWaylandBuffer *buffer);
gboolean meta_wayland_buffer_is_y_inverted (MetaWaylandBuffer *buffer); gboolean meta_wayland_buffer_is_y_inverted (MetaWaylandBuffer *buffer);
void meta_wayland_buffer_process_damage (MetaWaylandBuffer *buffer, void meta_wayland_buffer_process_damage (MetaWaylandBuffer *buffer,
CoglTexture *texture, CoglMultiPlaneTexture *texture,
cairo_region_t *region); cairo_region_t *region);
#endif /* META_WAYLAND_BUFFER_H */ #endif /* META_WAYLAND_BUFFER_H */

View File

@ -58,7 +58,7 @@ update_cursor_sprite_texture (MetaWaylandCursorSurface *cursor_surface)
MetaWaylandSurface *surface = MetaWaylandSurface *surface =
meta_wayland_surface_role_get_surface (META_WAYLAND_SURFACE_ROLE (cursor_surface)); meta_wayland_surface_role_get_surface (META_WAYLAND_SURFACE_ROLE (cursor_surface));
MetaCursorSprite *cursor_sprite = META_CURSOR_SPRITE (priv->cursor_sprite); MetaCursorSprite *cursor_sprite = META_CURSOR_SPRITE (priv->cursor_sprite);
CoglTexture *texture; CoglMultiPlaneTexture *texture;
if (!priv->cursor_renderer) if (!priv->cursor_renderer)
return; return;
@ -66,8 +66,13 @@ update_cursor_sprite_texture (MetaWaylandCursorSurface *cursor_surface)
texture = meta_wayland_surface_get_texture (surface); texture = meta_wayland_surface_get_texture (surface);
if (texture) 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, meta_cursor_sprite_set_texture (cursor_sprite,
texture, plane,
priv->hot_x * surface->scale, priv->hot_x * surface->scale,
priv->hot_y * surface->scale); priv->hot_y * surface->scale);
} }

View File

@ -56,8 +56,9 @@ struct _MetaWaylandDmaBufBuffer
int width; int width;
int height; int height;
uint32_t drm_format; uint32_t drm_format;
uint64_t drm_modifier;
bool is_y_inverted; bool is_y_inverted;
uint64_t drm_modifier[META_WAYLAND_DMA_BUF_MAX_FDS];
int fds[META_WAYLAND_DMA_BUF_MAX_FDS]; int fds[META_WAYLAND_DMA_BUF_MAX_FDS];
int offsets[META_WAYLAND_DMA_BUF_MAX_FDS]; int offsets[META_WAYLAND_DMA_BUF_MAX_FDS];
unsigned int strides[META_WAYLAND_DMA_BUF_MAX_FDS]; unsigned int strides[META_WAYLAND_DMA_BUF_MAX_FDS];
@ -65,6 +66,139 @@ struct _MetaWaylandDmaBufBuffer
G_DEFINE_TYPE (MetaWaylandDmaBufBuffer, meta_wayland_dma_buf_buffer, G_TYPE_OBJECT); G_DEFINE_TYPE (MetaWaylandDmaBufBuffer, meta_wayland_dma_buf_buffer, G_TYPE_OBJECT);
static CoglPixelFormat
drm_buffer_get_cogl_pixel_format (MetaWaylandDmaBufBuffer *dma_buf)
{
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 static gboolean
meta_wayland_dma_buf_realize_texture (MetaWaylandBuffer *buffer, meta_wayland_dma_buf_realize_texture (MetaWaylandBuffer *buffer,
GError **error) GError **error)
@ -76,137 +210,75 @@ meta_wayland_dma_buf_realize_texture (MetaWaylandBuffer *buffer,
EGLDisplay egl_display = cogl_egl_context_get_egl_display (cogl_context); EGLDisplay egl_display = cogl_egl_context_get_egl_display (cogl_context);
MetaWaylandDmaBufBuffer *dma_buf = buffer->dma_buf.dma_buf; MetaWaylandDmaBufBuffer *dma_buf = buffer->dma_buf.dma_buf;
CoglPixelFormat cogl_format; CoglPixelFormat cogl_format;
EGLImageKHR egl_image; CoglTextureComponents components[3];
CoglTexture2D *texture; CoglPixelFormat subformats[3];
EGLint attribs[64]; GPtrArray *planes;
int attr_idx = 0; guint i = 0, n_planes = 1;
if (buffer->dma_buf.texture) if (buffer->dma_buf.texture)
return TRUE; return TRUE;
switch (dma_buf->drm_format) cogl_format = drm_buffer_get_cogl_pixel_format (dma_buf);
if (cogl_format == COGL_PIXEL_FORMAT_ANY)
{ {
/* g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
* NOTE: The cogl_format here is only used for texture color channel
* swizzling as compared to COGL_PIXEL_FORMAT_ARGB. It is *not* used
* for accessing the buffer memory. EGL will access the buffer
* memory according to the DRM fourcc code. Cogl will not mmap
* and access the buffer memory at all.
*/
case DRM_FORMAT_XRGB8888:
cogl_format = COGL_PIXEL_FORMAT_RGB_888;
break;
case DRM_FORMAT_ARGB8888:
cogl_format = COGL_PIXEL_FORMAT_ARGB_8888_PRE;
break;
case DRM_FORMAT_ARGB2101010:
cogl_format = COGL_PIXEL_FORMAT_ARGB_2101010_PRE;
break;
case DRM_FORMAT_RGB565:
cogl_format = COGL_PIXEL_FORMAT_RGB_565;
break;
default:
g_set_error (error, G_IO_ERROR,
G_IO_ERROR_FAILED,
"Unsupported buffer format %d", dma_buf->drm_format); "Unsupported buffer format %d", dma_buf->drm_format);
return FALSE; return FALSE;
} }
attribs[attr_idx++] = EGL_WIDTH; n_planes = cogl_pixel_format_get_n_planes (cogl_format);
attribs[attr_idx++] = dma_buf->width; cogl_pixel_format_get_subformats (cogl_format, subformats);
attribs[attr_idx++] = EGL_HEIGHT; cogl_pixel_format_get_cogl_components (cogl_format, components);
attribs[attr_idx++] = dma_buf->height; planes = g_ptr_array_new_full (n_planes, cogl_object_unref);
attribs[attr_idx++] = EGL_LINUX_DRM_FOURCC_EXT;
attribs[attr_idx++] = dma_buf->drm_format;
attribs[attr_idx++] = EGL_DMA_BUF_PLANE0_FD_EXT; /* Each EGLImage is a plane in the final CoglMultiPlaneTexture */
attribs[attr_idx++] = dma_buf->fds[0]; for (i = 0; i < n_planes; i++)
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)
{ {
attribs[attr_idx++] = EGL_DMA_BUF_PLANE1_FD_EXT; EGLImageKHR egl_img;
attribs[attr_idx++] = dma_buf->fds[1]; CoglTexture2D *plane;
attribs[attr_idx++] = EGL_DMA_BUF_PLANE1_OFFSET_EXT;
attribs[attr_idx++] = dma_buf->offsets[1]; egl_img = create_egl_image_from_dmabuf (egl,
attribs[attr_idx++] = EGL_DMA_BUF_PLANE1_PITCH_EXT; egl_display,
attribs[attr_idx++] = dma_buf->strides[1]; dma_buf,
attribs[attr_idx++] = EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT; dma_buf->width, dma_buf->height,
attribs[attr_idx++] = dma_buf->drm_modifier & 0xffffffff; dma_buf->drm_format,
attribs[attr_idx++] = EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT; error);
attribs[attr_idx++] = dma_buf->drm_modifier >> 32; if (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,
subformats[i],
components[i],
egl_img,
error);
meta_egl_destroy_image (egl, egl_display, egl_img, NULL);
if (!plane)
goto on_error;
g_ptr_array_add (planes, plane);
} }
if (dma_buf->fds[2] >= 0) buffer->dma_buf.texture = cogl_multi_plane_texture_new (cogl_format,
{ (CoglTexture **) g_ptr_array_free (planes, FALSE),
attribs[attr_idx++] = EGL_DMA_BUF_PLANE2_FD_EXT; n_planes);
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->is_y_inverted = dma_buf->is_y_inverted; buffer->is_y_inverted = dma_buf->is_y_inverted;
return TRUE; return TRUE;
on_error:
g_ptr_array_free (planes, TRUE);
return FALSE;
} }
gboolean gboolean
meta_wayland_dma_buf_buffer_attach (MetaWaylandBuffer *buffer, meta_wayland_dma_buf_buffer_attach (MetaWaylandBuffer *buffer,
CoglTexture **texture, CoglMultiPlaneTexture **texture,
gboolean *changed_texture, gboolean *changed_texture,
GError **error) GError **error)
{ {
if (!meta_wayland_dma_buf_realize_texture (buffer, error)) if (!meta_wayland_dma_buf_realize_texture (buffer, error))
return FALSE; return FALSE;
@ -260,8 +332,8 @@ buffer_params_add (struct wl_client *client,
return; return;
} }
if (dma_buf->drm_modifier != DRM_FORMAT_MOD_INVALID && if (dma_buf->drm_modifier[plane_idx] != DRM_FORMAT_MOD_INVALID &&
dma_buf->drm_modifier != drm_modifier) dma_buf->drm_modifier[plane_idx] != drm_modifier)
{ {
wl_resource_post_error (resource, wl_resource_post_error (resource,
ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_WL_BUFFER, ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_WL_BUFFER,
@ -269,8 +341,9 @@ buffer_params_add (struct wl_client *client,
return; return;
} }
dma_buf->drm_modifier = drm_modifier;
dma_buf->fds[plane_idx] = fd; dma_buf->fds[plane_idx] = fd;
dma_buf->drm_modifier[plane_idx] = drm_modifier;
dma_buf->offsets[plane_idx] = offset; dma_buf->offsets[plane_idx] = offset;
dma_buf->strides[plane_idx] = stride; dma_buf->strides[plane_idx] = stride;
} }
@ -550,6 +623,9 @@ dma_buf_bind (struct wl_client *client,
send_modifiers (resource, DRM_FORMAT_XRGB8888); send_modifiers (resource, DRM_FORMAT_XRGB8888);
send_modifiers (resource, DRM_FORMAT_ARGB2101010); send_modifiers (resource, DRM_FORMAT_ARGB2101010);
send_modifiers (resource, DRM_FORMAT_RGB565); send_modifiers (resource, DRM_FORMAT_RGB565);
send_modifiers (resource, DRM_FORMAT_AYUV);
send_modifiers (resource, DRM_FORMAT_NV12);
send_modifiers (resource, DRM_FORMAT_YUV422);
} }
gboolean gboolean
@ -598,10 +674,12 @@ meta_wayland_dma_buf_buffer_init (MetaWaylandDmaBufBuffer *dma_buf)
{ {
int i; int i;
dma_buf->drm_modifier = DRM_FORMAT_MOD_INVALID;
for (i = 0; i < META_WAYLAND_DMA_BUF_MAX_FDS; i++) 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 static void

View File

@ -42,10 +42,10 @@ typedef struct _MetaWaylandDmaBufBuffer MetaWaylandDmaBufBuffer;
gboolean meta_wayland_dma_buf_init (MetaWaylandCompositor *compositor); gboolean meta_wayland_dma_buf_init (MetaWaylandCompositor *compositor);
gboolean gboolean
meta_wayland_dma_buf_buffer_attach (MetaWaylandBuffer *buffer, meta_wayland_dma_buf_buffer_attach (MetaWaylandBuffer *buffer,
CoglTexture **texture, CoglMultiPlaneTexture **texture,
gboolean *changed_texture, gboolean *changed_texture,
GError **error); GError **error);
MetaWaylandDmaBufBuffer * MetaWaylandDmaBufBuffer *
meta_wayland_dma_buf_from_buffer (MetaWaylandBuffer *buffer); meta_wayland_dma_buf_from_buffer (MetaWaylandBuffer *buffer);

View File

@ -132,7 +132,7 @@ struct _MetaWaylandEglStream
EGLStreamKHR egl_stream; EGLStreamKHR egl_stream;
MetaWaylandBuffer *buffer; MetaWaylandBuffer *buffer;
CoglTexture2D *texture; CoglMultiPlaneTexture *texture;
gboolean is_y_inverted; gboolean is_y_inverted;
}; };
@ -183,7 +183,7 @@ stream_texture_destroyed (gpointer data)
} }
static gboolean static gboolean
alloc_egl_stream_texture (CoglTexture2D *texture, alloc_egl_stream_texture (CoglTexture2D *texture_2d,
gpointer user_data, gpointer user_data,
GError **error) GError **error)
{ {
@ -199,7 +199,7 @@ alloc_egl_stream_texture (CoglTexture2D *texture,
error); error);
} }
CoglTexture2D * CoglMultiPlaneTexture *
meta_wayland_egl_stream_create_texture (MetaWaylandEglStream *stream, meta_wayland_egl_stream_create_texture (MetaWaylandEglStream *stream,
GError **error) GError **error)
{ {
@ -208,7 +208,7 @@ meta_wayland_egl_stream_create_texture (MetaWaylandEglStream *stream,
ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend); ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
CoglContext *cogl_context = clutter_backend_get_cogl_context (clutter_backend); CoglContext *cogl_context = clutter_backend_get_cogl_context (clutter_backend);
EGLDisplay egl_display = cogl_egl_context_get_egl_display (cogl_context); EGLDisplay egl_display = cogl_egl_context_get_egl_display (cogl_context);
CoglTexture2D *texture; CoglTexture2D *texture_2d;
int width, height; int width, height;
int y_inverted; int y_inverted;
@ -230,29 +230,30 @@ meta_wayland_egl_stream_create_texture (MetaWaylandEglStream *stream,
NULL)) NULL))
y_inverted = EGL_TRUE; y_inverted = EGL_TRUE;
texture = texture_2d =
cogl_texture_2d_new_from_egl_image_external (cogl_context, cogl_texture_2d_new_from_egl_image_external (cogl_context,
width, height, width, height,
alloc_egl_stream_texture, alloc_egl_stream_texture,
g_object_ref (stream), g_object_ref (stream),
stream_texture_destroyed, stream_texture_destroyed,
error); error);
if (!texture) if (!texture_2d)
{ {
g_object_unref (stream); g_object_unref (stream);
return NULL; 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; 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; stream->is_y_inverted = !!y_inverted;
return texture; return stream->texture;
} }
gboolean gboolean

View File

@ -45,8 +45,8 @@ MetaWaylandEglStream * meta_wayland_egl_stream_new (MetaWaylandBuffer *buffer,
gboolean meta_wayland_egl_stream_attach (MetaWaylandEglStream *stream, gboolean meta_wayland_egl_stream_attach (MetaWaylandEglStream *stream,
GError **error); GError **error);
CoglTexture2D * meta_wayland_egl_stream_create_texture (MetaWaylandEglStream *stream, CoglMultiPlaneTexture * meta_wayland_egl_stream_create_texture (MetaWaylandEglStream *stream,
GError **error); GError **error);
CoglSnippet * meta_wayland_egl_stream_create_snippet (void); CoglSnippet * meta_wayland_egl_stream_create_snippet (void);
gboolean meta_wayland_egl_stream_is_y_inverted (MetaWaylandEglStream *stream); gboolean meta_wayland_egl_stream_is_y_inverted (MetaWaylandEglStream *stream);

View File

@ -153,7 +153,7 @@ meta_wayland_shell_surface_surface_commit (MetaWaylandSurfaceRole *surface_role
MetaWaylandSurfaceRoleClass *surface_role_class; MetaWaylandSurfaceRoleClass *surface_role_class;
MetaWindow *window; MetaWindow *window;
MetaWaylandBuffer *buffer; MetaWaylandBuffer *buffer;
CoglTexture *texture; CoglMultiPlaneTexture *texture;
double scale; double scale;
surface_role_class = 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); scale = meta_wayland_actor_surface_calculate_scale (actor_surface);
texture = meta_wayland_surface_get_texture (surface); texture = meta_wayland_surface_get_texture (surface);
window->buffer_rect.width = cogl_texture_get_width (texture) * scale; window->buffer_rect.width = cogl_multi_plane_texture_get_width (texture) * scale;
window->buffer_rect.height = cogl_texture_get_height (texture) * scale; window->buffer_rect.height = cogl_multi_plane_texture_get_height (texture) * scale;
} }
static void static void

View File

@ -246,7 +246,7 @@ get_buffer_width (MetaWaylandSurface *surface)
MetaWaylandBuffer *buffer = meta_wayland_surface_get_buffer (surface); MetaWaylandBuffer *buffer = meta_wayland_surface_get_buffer (surface);
if (buffer) if (buffer)
return cogl_texture_get_width (surface->texture); return cogl_multi_plane_texture_get_width (surface->texture);
else else
return 0; return 0;
} }
@ -257,7 +257,7 @@ get_buffer_height (MetaWaylandSurface *surface)
MetaWaylandBuffer *buffer = meta_wayland_surface_get_buffer (surface); MetaWaylandBuffer *buffer = meta_wayland_surface_get_buffer (surface);
if (buffer) if (buffer)
return cogl_texture_get_height (surface->texture); return cogl_multi_plane_texture_get_height (surface->texture);
else else
return 0; return 0;
} }
@ -721,7 +721,7 @@ meta_wayland_surface_apply_pending_state (MetaWaylandSurface *surface,
if (changed_texture && meta_wayland_surface_get_actor (surface)) if (changed_texture && meta_wayland_surface_get_actor (surface))
{ {
MetaShapedTexture *stex; MetaShapedTexture *stex;
CoglTexture *texture; CoglMultiPlaneTexture *texture;
CoglSnippet *snippet; CoglSnippet *snippet;
gboolean is_y_inverted; gboolean is_y_inverted;
@ -1846,7 +1846,7 @@ meta_wayland_surface_is_shortcuts_inhibited (MetaWaylandSurface *surface,
return g_hash_table_contains (surface->shortcut_inhibited_seats, seat); return g_hash_table_contains (surface->shortcut_inhibited_seats, seat);
} }
CoglTexture * CoglMultiPlaneTexture *
meta_wayland_surface_get_texture (MetaWaylandSurface *surface) meta_wayland_surface_get_texture (MetaWaylandSurface *surface)
{ {
return surface->texture; return surface->texture;

View File

@ -149,7 +149,7 @@ struct _MetaWaylandSurface
GHashTable *outputs_to_destroy_notify_id; GHashTable *outputs_to_destroy_notify_id;
MetaMonitorTransform buffer_transform; MetaMonitorTransform buffer_transform;
CoglTexture *texture; CoglMultiPlaneTexture *texture;
/* Buffer reference state. */ /* Buffer reference state. */
struct { struct {
@ -319,7 +319,7 @@ void meta_wayland_surface_restore_shortcuts (MetaWaylandSurface *
gboolean meta_wayland_surface_is_shortcuts_inhibited (MetaWaylandSurface *surface, gboolean meta_wayland_surface_is_shortcuts_inhibited (MetaWaylandSurface *surface,
MetaWaylandSeat *seat); 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); MetaSurfaceActor * meta_wayland_surface_get_actor (MetaWaylandSurface *surface);

View File

@ -305,6 +305,26 @@ meta_wayland_log_func (const char *fmt,
g_free (str); 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 static void
meta_wayland_compositor_init (MetaWaylandCompositor *compositor) meta_wayland_compositor_init (MetaWaylandCompositor *compositor)
{ {
@ -317,6 +337,8 @@ meta_wayland_compositor_init (MetaWaylandCompositor *compositor)
compositor->wayland_display = wl_display_create (); compositor->wayland_display = wl_display_create ();
if (compositor->wayland_display == NULL) if (compositor->wayland_display == NULL)
g_error ("Failed to create the global wl_display"); g_error ("Failed to create the global wl_display");
add_supported_shm_formats (compositor->wayland_display);
} }
static void static void