[mutter] shaped-texture: Get transformed textures pixels via offscreen
- From: Georges Basile Stavracas Neto <gbsneto src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [mutter] shaped-texture: Get transformed textures pixels via offscreen
- Date: Thu, 3 Jan 2019 11:20:26 +0000 (UTC)
commit c84d7ebc6d208b082859cb61b7157db0eedda2cb
Author: Jonas Ã…dahl <jadahl gmail com>
Date: Thu Dec 20 17:34:18 2018 +0100
shaped-texture: Get transformed textures pixels via offscreen
When a texture is transformed in any way (e.g. Wayland buffer
transforms), we cannot just fetch the pixels from the texture directly
and be done with it, as that will result in getting the untransformed
pixels.
To properly get the pixels in their right form, first draw to an
offscreen framebuffer, using the same method as when painting on the
stage, then read from the framebuffer into a cairo image surface.
https://gitlab.gnome.org/GNOME/mutter/merge_requests/362
Fixes: https://gitlab.gnome.org/GNOME/mutter/issues/408
src/compositor/meta-shaped-texture.c | 148 ++++++++++++++++++++++++++++++++++-
1 file changed, 145 insertions(+), 3 deletions(-)
---
diff --git a/src/compositor/meta-shaped-texture.c b/src/compositor/meta-shaped-texture.c
index 1f38dbdfd..955375995 100644
--- a/src/compositor/meta-shaped-texture.c
+++ b/src/compositor/meta-shaped-texture.c
@@ -36,6 +36,7 @@
#include "compositor/meta-cullable.h"
#include "compositor/meta-texture-tower.h"
#include "compositor/region-utils.h"
+#include "core/boxes-private.h"
#include "meta/meta-shaped-texture.h"
/* MAX_MIPMAPPING_FPS needs to be as small as possible for the best GPU
@@ -1038,6 +1039,129 @@ meta_shaped_texture_set_transform (MetaShapedTexture *stex,
invalidate_size (stex);
}
+static gboolean
+should_get_via_offscreen (MetaShapedTexture *stex)
+{
+ switch (stex->transform)
+ {
+ case META_MONITOR_TRANSFORM_90:
+ case META_MONITOR_TRANSFORM_180:
+ case META_MONITOR_TRANSFORM_270:
+ case META_MONITOR_TRANSFORM_FLIPPED:
+ case META_MONITOR_TRANSFORM_FLIPPED_90:
+ case META_MONITOR_TRANSFORM_FLIPPED_180:
+ case META_MONITOR_TRANSFORM_FLIPPED_270:
+ return TRUE;
+ case META_MONITOR_TRANSFORM_NORMAL:
+ break;
+ }
+
+ return FALSE;
+}
+
+static cairo_surface_t *
+get_image_via_offscreen (MetaShapedTexture *stex,
+ cairo_rectangle_int_t *clip)
+{
+ 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;
+ 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 = stex->dst_width;
+ fb_height = stex->dst_height;
+ }
+ else
+ {
+ fb_width = _cogl_util_next_p2 (stex->dst_width);
+ fb_height = _cogl_util_next_p2 (stex->dst_height);
+ }
+
+ if (!clip)
+ {
+ fallback_clip = (cairo_rectangle_int_t) {
+ .width = stex->dst_width,
+ .height = stex->dst_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 != stex->dst_width || fb_height != stex->dst_height)
+ {
+ CoglSubTexture *sub_texture;
+
+ sub_texture = cogl_sub_texture_new (cogl_context,
+ image_texture,
+ 0, 0,
+ stex->dst_width, stex->dst_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 / (stex->dst_width / 2.0),
+ -1.0 / (stex->dst_height / 2.0), 0);
+ cogl_matrix_translate (&projection_matrix,
+ -(stex->dst_width / 2.0),
+ -(stex->dst_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, stex->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:
* @stex: A #MetaShapedTexture
@@ -1058,7 +1182,6 @@ meta_shaped_texture_get_image (MetaShapedTexture *stex,
{
cairo_rectangle_int_t *transformed_clip = NULL;
CoglTexture *texture, *mask_texture;
- cairo_rectangle_int_t texture_rect = { 0, 0, 0, 0 };
cairo_surface_t *surface;
g_return_val_if_fail (META_IS_SHAPED_TEXTURE (stex), NULL);
@@ -1068,17 +1191,36 @@ meta_shaped_texture_get_image (MetaShapedTexture *stex,
if (texture == NULL)
return NULL;
+ ensure_size_valid (stex);
+
+ if (stex->dst_width == 0 || stex->dst_height == 0)
+ return NULL;
if (clip != NULL)
{
+ double tex_scale;
+ cairo_rectangle_int_t dst_rect;
+
transformed_clip = alloca (sizeof (cairo_rectangle_int_t));
- *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 (clip, 1.0 / tex_scale,
+ META_ROUNDING_STRATEGY_GROW,
+ transformed_clip);
+
+ dst_rect = (cairo_rectangle_int_t) {
+ .width = stex->dst_width,
+ .height = stex->dst_height,
+ };
+
+ if (!meta_rectangle_intersect (&dst_rect, transformed_clip,
transformed_clip))
return NULL;
}
+ if (should_get_via_offscreen (stex))
+ return get_image_via_offscreen (stex, transformed_clip);
+
if (transformed_clip)
texture = cogl_texture_new_from_sub_texture (texture,
transformed_clip->x,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]