[mutter/wip/rstrode/rhel-8.0.0: 69/117] shaped-texture: Draw external textures via offscreen



commit 58c2c2c444543ebad964b9c0633f45defc1e4114
Author: Jonas Ã…dahl <jadahl gmail com>
Date:   Thu Dec 20 17:34:18 2018 +0100

    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

 src/compositor/meta-shaped-texture.c | 136 ++++++++++++++++++++++++++++++++++-
 1 file changed, 134 insertions(+), 2 deletions(-)
---
diff --git a/src/compositor/meta-shaped-texture.c b/src/compositor/meta-shaped-texture.c
index 823bd47f2..d8c250fc9 100644
--- a/src/compositor/meta-shaped-texture.c
+++ b/src/compositor/meta-shaped-texture.c
@@ -35,6 +35,7 @@
 
 #include "clutter-utils.h"
 #include "meta-texture-tower.h"
+#include "core/boxes-private.h"
 
 #include "meta-cullable.h"
 
@@ -906,6 +907,121 @@ meta_shaped_texture_get_opaque_region (MetaShapedTexture *stex)
   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:
  * @stex: A #MetaShapedTexture
@@ -927,7 +1043,6 @@ meta_shaped_texture_get_image (MetaShapedTexture     *stex,
   MetaShapedTexturePrivate *priv = stex->priv;
   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);
@@ -937,17 +1052,34 @@ meta_shaped_texture_get_image (MetaShapedTexture     *stex,
   if (texture == NULL)
     return NULL;
 
+  if (priv->tex_width == 0 || priv->tex_height == 0)
+    return NULL;
 
   if (clip != NULL)
     {
+      double tex_scale;
+      cairo_rectangle_int_t tex_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 (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))
         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]