mirror of
https://github.com/brl/mutter.git
synced 2024-11-24 09:00:42 -05:00
shaped-texture: Draw external textures via offscreen
EGLStream textures are imported as GL_TEXTURE_EXTERNAL_OES and reading pixels directly from them is not supported. To make it possible to get pixels, create an offscreen framebuffer and paint the actor to it, then read pixels from the framebuffer instead of the texture directly. https://gitlab.gnome.org/GNOME/mutter/merge_requests/362
This commit is contained in:
parent
1fe3adcd95
commit
58c2c2c444
@ -35,6 +35,7 @@
|
|||||||
|
|
||||||
#include "clutter-utils.h"
|
#include "clutter-utils.h"
|
||||||
#include "meta-texture-tower.h"
|
#include "meta-texture-tower.h"
|
||||||
|
#include "core/boxes-private.h"
|
||||||
|
|
||||||
#include "meta-cullable.h"
|
#include "meta-cullable.h"
|
||||||
|
|
||||||
@ -906,6 +907,121 @@ meta_shaped_texture_get_opaque_region (MetaShapedTexture *stex)
|
|||||||
return priv->opaque_region;
|
return priv->opaque_region;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
should_get_via_offscreen (MetaShapedTexture *stex)
|
||||||
|
{
|
||||||
|
MetaShapedTexturePrivate *priv = stex->priv;
|
||||||
|
|
||||||
|
if (!cogl_texture_is_get_data_supported (priv->texture))
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static cairo_surface_t *
|
||||||
|
get_image_via_offscreen (MetaShapedTexture *stex,
|
||||||
|
cairo_rectangle_int_t *clip)
|
||||||
|
{
|
||||||
|
MetaShapedTexturePrivate *priv = stex->priv;
|
||||||
|
ClutterBackend *clutter_backend = clutter_get_default_backend ();
|
||||||
|
CoglContext *cogl_context =
|
||||||
|
clutter_backend_get_cogl_context (clutter_backend);
|
||||||
|
CoglTexture *image_texture;
|
||||||
|
GError *error = NULL;
|
||||||
|
CoglOffscreen *offscreen;
|
||||||
|
CoglFramebuffer *fb;
|
||||||
|
CoglMatrix projection_matrix;
|
||||||
|
unsigned int fb_width, fb_height;
|
||||||
|
cairo_rectangle_int_t fallback_clip;
|
||||||
|
CoglColor clear_color;
|
||||||
|
cairo_surface_t *surface;
|
||||||
|
|
||||||
|
if (cogl_has_feature (cogl_context, COGL_FEATURE_ID_TEXTURE_NPOT))
|
||||||
|
{
|
||||||
|
fb_width = priv->tex_width;
|
||||||
|
fb_height = priv->tex_height;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fb_width = clutter_util_next_p2 (priv->tex_width);
|
||||||
|
fb_height = clutter_util_next_p2 (priv->tex_height);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!clip)
|
||||||
|
{
|
||||||
|
fallback_clip = (cairo_rectangle_int_t) {
|
||||||
|
.width = priv->tex_width,
|
||||||
|
.height = priv->tex_height,
|
||||||
|
};
|
||||||
|
clip = &fallback_clip;
|
||||||
|
}
|
||||||
|
|
||||||
|
image_texture =
|
||||||
|
COGL_TEXTURE (cogl_texture_2d_new_with_size (cogl_context,
|
||||||
|
fb_width, fb_height));
|
||||||
|
cogl_primitive_texture_set_auto_mipmap (COGL_PRIMITIVE_TEXTURE (image_texture),
|
||||||
|
FALSE);
|
||||||
|
if (!cogl_texture_allocate (COGL_TEXTURE (image_texture), &error))
|
||||||
|
{
|
||||||
|
g_error_free (error);
|
||||||
|
cogl_object_unref (image_texture);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fb_width != priv->tex_width || fb_height != priv->tex_height)
|
||||||
|
{
|
||||||
|
CoglSubTexture *sub_texture;
|
||||||
|
|
||||||
|
sub_texture = cogl_sub_texture_new (cogl_context,
|
||||||
|
image_texture,
|
||||||
|
0, 0,
|
||||||
|
priv->tex_width, priv->tex_height);
|
||||||
|
cogl_object_unref (image_texture);
|
||||||
|
image_texture = COGL_TEXTURE (sub_texture);
|
||||||
|
}
|
||||||
|
|
||||||
|
offscreen = cogl_offscreen_new_with_texture (COGL_TEXTURE (image_texture));
|
||||||
|
fb = COGL_FRAMEBUFFER (offscreen);
|
||||||
|
cogl_object_unref (image_texture);
|
||||||
|
if (!cogl_framebuffer_allocate (fb, &error))
|
||||||
|
{
|
||||||
|
g_error_free (error);
|
||||||
|
cogl_object_unref (fb);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
cogl_framebuffer_push_matrix (fb);
|
||||||
|
cogl_matrix_init_identity (&projection_matrix);
|
||||||
|
cogl_matrix_scale (&projection_matrix,
|
||||||
|
1.0 / (priv->tex_width / 2.0),
|
||||||
|
-1.0 / (priv->tex_height / 2.0), 0);
|
||||||
|
cogl_matrix_translate (&projection_matrix,
|
||||||
|
-(priv->tex_width / 2.0),
|
||||||
|
-(priv->tex_height / 2.0), 0);
|
||||||
|
|
||||||
|
cogl_framebuffer_set_projection_matrix (fb, &projection_matrix);
|
||||||
|
|
||||||
|
cogl_color_init_from_4ub (&clear_color, 0, 0, 0, 0);
|
||||||
|
cogl_framebuffer_clear (fb, COGL_BUFFER_BIT_COLOR, &clear_color);
|
||||||
|
|
||||||
|
do_paint (stex, fb, priv->texture, NULL);
|
||||||
|
|
||||||
|
cogl_framebuffer_pop_matrix (fb);
|
||||||
|
|
||||||
|
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
|
||||||
|
clip->width, clip->height);
|
||||||
|
cogl_framebuffer_read_pixels (fb,
|
||||||
|
clip->x, clip->y,
|
||||||
|
clip->width, clip->height,
|
||||||
|
CLUTTER_CAIRO_FORMAT_ARGB32,
|
||||||
|
cairo_image_surface_get_data (surface));
|
||||||
|
cogl_object_unref (fb);
|
||||||
|
|
||||||
|
cairo_surface_mark_dirty (surface);
|
||||||
|
|
||||||
|
return surface;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* meta_shaped_texture_get_image:
|
* meta_shaped_texture_get_image:
|
||||||
* @stex: A #MetaShapedTexture
|
* @stex: A #MetaShapedTexture
|
||||||
@ -927,7 +1043,6 @@ meta_shaped_texture_get_image (MetaShapedTexture *stex,
|
|||||||
MetaShapedTexturePrivate *priv = stex->priv;
|
MetaShapedTexturePrivate *priv = stex->priv;
|
||||||
cairo_rectangle_int_t *transformed_clip = NULL;
|
cairo_rectangle_int_t *transformed_clip = NULL;
|
||||||
CoglTexture *texture, *mask_texture;
|
CoglTexture *texture, *mask_texture;
|
||||||
cairo_rectangle_int_t texture_rect = { 0, 0, 0, 0 };
|
|
||||||
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);
|
||||||
@ -937,17 +1052,34 @@ meta_shaped_texture_get_image (MetaShapedTexture *stex,
|
|||||||
if (texture == NULL)
|
if (texture == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
if (priv->tex_width == 0 || priv->tex_height == 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
if (clip != NULL)
|
if (clip != NULL)
|
||||||
{
|
{
|
||||||
|
double tex_scale;
|
||||||
|
cairo_rectangle_int_t tex_rect;
|
||||||
|
|
||||||
transformed_clip = alloca (sizeof (cairo_rectangle_int_t));
|
transformed_clip = alloca (sizeof (cairo_rectangle_int_t));
|
||||||
*transformed_clip = *clip;
|
*transformed_clip = *clip;
|
||||||
|
|
||||||
if (!meta_rectangle_intersect (&texture_rect, transformed_clip,
|
clutter_actor_get_scale (CLUTTER_ACTOR (stex), &tex_scale, NULL);
|
||||||
|
meta_rectangle_scale_double (transformed_clip, 1.0 / tex_scale,
|
||||||
|
META_ROUNDING_STRATEGY_GROW);
|
||||||
|
|
||||||
|
tex_rect = (cairo_rectangle_int_t) {
|
||||||
|
.width = priv->tex_width,
|
||||||
|
.height = priv->tex_height,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!meta_rectangle_intersect (&tex_rect, transformed_clip,
|
||||||
transformed_clip))
|
transformed_clip))
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (should_get_via_offscreen (stex))
|
||||||
|
return get_image_via_offscreen (stex, transformed_clip);
|
||||||
|
|
||||||
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,
|
||||||
|
Loading…
Reference in New Issue
Block a user