[mutter/wip/texture-purge-on-nvidia: 61/71] shaped-texture-get-image-via-offscreen.patch



commit af61b6695385138725219dcc5b814bcaf763a4a1
Author: Ray Strode <rstrode redhat com>
Date:   Mon Jan 14 10:06:58 2019 -0500

    shaped-texture-get-image-via-offscreen.patch

 cogl/cogl/cogl-atlas-texture.c                   |   3 +-
 cogl/cogl/cogl-driver.h                          |   3 +
 cogl/cogl/cogl-sub-texture.c                     |  11 +-
 cogl/cogl/cogl-texture-2d-sliced.c               |   3 +-
 cogl/cogl/cogl-texture-2d.c                      |  12 +-
 cogl/cogl/cogl-texture-3d.c                      |   3 +-
 cogl/cogl/cogl-texture-private.h                 |   2 +
 cogl/cogl/cogl-texture-rectangle.c               |   3 +-
 cogl/cogl/cogl-texture.c                         |   9 +
 cogl/cogl/cogl-texture.h                         |   6 +
 cogl/cogl/driver/gl/cogl-texture-2d-gl-private.h |   3 +
 cogl/cogl/driver/gl/cogl-texture-2d-gl.c         |  20 +-
 cogl/cogl/driver/gl/gl/cogl-driver-gl.c          |   1 +
 cogl/cogl/driver/gl/gles/cogl-driver-gles.c      |   1 +
 cogl/cogl/driver/nop/cogl-driver-nop.c           |   1 +
 cogl/cogl/winsys/cogl-texture-pixmap-x11.c       |   3 +-
 src/compositor/clutter-utils.c                   |   9 +-
 src/compositor/clutter-utils.h                   |   9 +-
 src/compositor/meta-background-actor.c           |   7 +-
 src/compositor/meta-shaped-texture.c             | 269 ++++++++++++++++++-----
 src/compositor/meta-window-group.c               |   6 +-
 src/core/boxes-private.h                         |  10 +
 src/core/boxes.c                                 |  22 ++
 23 files changed, 338 insertions(+), 78 deletions(-)
---
diff --git a/cogl/cogl/cogl-atlas-texture.c b/cogl/cogl/cogl-atlas-texture.c
index 97bb84a6a..1a1f99b11 100644
--- a/cogl/cogl/cogl-atlas-texture.c
+++ b/cogl/cogl/cogl-atlas-texture.c
@@ -1043,5 +1043,6 @@ cogl_atlas_texture_vtable =
     _cogl_atlas_texture_get_gl_format,
     _cogl_atlas_texture_get_type,
     NULL, /* is_foreign */
-    NULL /* set_auto_mipmap */
+    NULL, /* set_auto_mipmap */
+    NULL  /* is_get_data_supported */
   };
diff --git a/cogl/cogl/cogl-driver.h b/cogl/cogl/cogl-driver.h
index 85aa0d870..33a7598a9 100644
--- a/cogl/cogl/cogl-driver.h
+++ b/cogl/cogl/cogl-driver.h
@@ -210,6 +210,9 @@ struct _CoglDriverVtable
                            int rowstride,
                            uint8_t *data);
 
+  CoglBool
+  (* texture_2d_is_get_data_supported) (CoglTexture2D *tex_2d);
+
   /* Prepares for drawing by flushing the journal, framebuffer state,
    * pipeline state and attribute state.
    */
diff --git a/cogl/cogl/cogl-sub-texture.c b/cogl/cogl/cogl-sub-texture.c
index 9d7abea90..c3b436140 100644
--- a/cogl/cogl/cogl-sub-texture.c
+++ b/cogl/cogl/cogl-sub-texture.c
@@ -454,6 +454,14 @@ _cogl_sub_texture_get_type (CoglTexture *tex)
   return _cogl_texture_get_type (sub_tex->full_texture);
 }
 
+static CoglBool
+_cogl_sub_texture_is_get_data_supported (CoglTexture *tex)
+{
+  CoglSubTexture *sub_tex = COGL_SUB_TEXTURE (tex);
+
+  return cogl_texture_is_get_data_supported (sub_tex->full_texture);
+}
+
 static const CoglTextureVtable
 cogl_sub_texture_vtable =
   {
@@ -476,5 +484,6 @@ cogl_sub_texture_vtable =
     _cogl_sub_texture_get_gl_format,
     _cogl_sub_texture_get_type,
     NULL, /* is_foreign */
-    NULL /* set_auto_mipmap */
+    NULL, /* set_auto_mipmap */
+    _cogl_sub_texture_is_get_data_supported
   };
diff --git a/cogl/cogl/cogl-texture-2d-sliced.c b/cogl/cogl/cogl-texture-2d-sliced.c
index 4f586cde7..458b29ce5 100644
--- a/cogl/cogl/cogl-texture-2d-sliced.c
+++ b/cogl/cogl/cogl-texture-2d-sliced.c
@@ -1542,5 +1542,6 @@ cogl_texture_2d_sliced_vtable =
     _cogl_texture_2d_sliced_get_gl_format,
     _cogl_texture_2d_sliced_get_type,
     _cogl_texture_2d_sliced_is_foreign,
-    NULL /* set_auto_mipmap */
+    NULL, /* set_auto_mipmap */
+    NULL  /* is_get_data_supported */
   };
diff --git a/cogl/cogl/cogl-texture-2d.c b/cogl/cogl/cogl-texture-2d.c
index 663125890..0e4a73de0 100644
--- a/cogl/cogl/cogl-texture-2d.c
+++ b/cogl/cogl/cogl-texture-2d.c
@@ -94,6 +94,15 @@ _cogl_texture_2d_set_auto_mipmap (CoglTexture *tex,
   tex_2d->auto_mipmap = value;
 }
 
+static CoglBool
+_cogl_texture_2d_is_get_data_supported (CoglTexture *tex)
+{
+  CoglTexture2D *tex_2d = COGL_TEXTURE_2D (tex);
+  CoglContext *ctx = tex->context;
+
+  return ctx->driver_vtable->texture_2d_is_get_data_supported (tex_2d);
+}
+
 CoglTexture2D *
 _cogl_texture_2d_create_base (CoglContext *ctx,
                               int width,
@@ -693,5 +702,6 @@ cogl_texture_2d_vtable =
     _cogl_texture_2d_get_gl_format,
     _cogl_texture_2d_get_type,
     _cogl_texture_2d_is_foreign,
-    _cogl_texture_2d_set_auto_mipmap
+    _cogl_texture_2d_set_auto_mipmap,
+    _cogl_texture_2d_is_get_data_supported
   };
diff --git a/cogl/cogl/cogl-texture-3d.c b/cogl/cogl/cogl-texture-3d.c
index 5644119d7..00b3447ec 100644
--- a/cogl/cogl/cogl-texture-3d.c
+++ b/cogl/cogl/cogl-texture-3d.c
@@ -755,5 +755,6 @@ cogl_texture_3d_vtable =
     _cogl_texture_3d_get_gl_format,
     _cogl_texture_3d_get_type,
     NULL, /* is_foreign */
-    _cogl_texture_3d_set_auto_mipmap
+    _cogl_texture_3d_set_auto_mipmap,
+    NULL  /* is_get_data_supported */
   };
diff --git a/cogl/cogl/cogl-texture-private.h b/cogl/cogl/cogl-texture-private.h
index 742983e2d..44100f0b7 100644
--- a/cogl/cogl/cogl-texture-private.h
+++ b/cogl/cogl/cogl-texture-private.h
@@ -149,6 +149,8 @@ struct _CoglTextureVtable
   /* Only needs to be implemented if is_primitive == TRUE */
   void (* set_auto_mipmap) (CoglTexture *texture,
                             CoglBool value);
+
+  CoglBool (* is_get_data_supported) (CoglTexture *texture);
 };
 
 typedef enum _CoglTextureSoureType {
diff --git a/cogl/cogl/cogl-texture-rectangle.c b/cogl/cogl/cogl-texture-rectangle.c
index cc2e642d3..0179324a4 100644
--- a/cogl/cogl/cogl-texture-rectangle.c
+++ b/cogl/cogl/cogl-texture-rectangle.c
@@ -773,5 +773,6 @@ cogl_texture_rectangle_vtable =
     _cogl_texture_rectangle_get_gl_format,
     _cogl_texture_rectangle_get_type,
     _cogl_texture_rectangle_is_foreign,
-    _cogl_texture_rectangle_set_auto_mipmap
+    _cogl_texture_rectangle_set_auto_mipmap,
+    NULL  /* is_get_data_supported */
   };
diff --git a/cogl/cogl/cogl-texture.c b/cogl/cogl/cogl-texture.c
index e2d37e225..eef2abdbe 100644
--- a/cogl/cogl/cogl-texture.c
+++ b/cogl/cogl/cogl-texture.c
@@ -205,6 +205,15 @@ _cogl_texture_is_foreign (CoglTexture *texture)
     return FALSE;
 }
 
+CoglBool
+cogl_texture_is_get_data_supported (CoglTexture *texture)
+{
+  if (texture->vtable->is_get_data_supported)
+    return texture->vtable->is_get_data_supported (texture);
+  else
+    return TRUE;
+}
+
 unsigned int
 cogl_texture_get_width (CoglTexture *texture)
 {
diff --git a/cogl/cogl/cogl-texture.h b/cogl/cogl/cogl-texture.h
index ef7d14281..67647aa9c 100644
--- a/cogl/cogl/cogl-texture.h
+++ b/cogl/cogl/cogl-texture.h
@@ -511,6 +511,12 @@ CoglBool
 cogl_texture_allocate (CoglTexture *texture,
                        CoglError **error);
 
+/**
+ * cogl_texture_is_get_data_supported: (skip)
+ */
+CoglBool
+cogl_texture_is_get_data_supported (CoglTexture *texture);
+
 COGL_END_DECLS
 
 #endif /* __COGL_TEXTURE_H__ */
diff --git a/cogl/cogl/driver/gl/cogl-texture-2d-gl-private.h 
b/cogl/cogl/driver/gl/cogl-texture-2d-gl-private.h
index e5c658534..1379e9a93 100644
--- a/cogl/cogl/driver/gl/cogl-texture-2d-gl-private.h
+++ b/cogl/cogl/driver/gl/cogl-texture-2d-gl-private.h
@@ -116,4 +116,7 @@ _cogl_texture_2d_gl_get_data (CoglTexture2D *tex_2d,
                               int rowstride,
                               uint8_t *data);
 
+CoglBool
+_cogl_texture_2d_gl_is_get_data_supported (CoglTexture2D *tex_2d);
+
 #endif /* _COGL_TEXTURE_2D_GL_PRIVATE_H_ */
diff --git a/cogl/cogl/driver/gl/cogl-texture-2d-gl.c b/cogl/cogl/driver/gl/cogl-texture-2d-gl.c
index d1eff4507..f04e3ebca 100644
--- a/cogl/cogl/driver/gl/cogl-texture-2d-gl.c
+++ b/cogl/cogl/driver/gl/cogl-texture-2d-gl.c
@@ -470,7 +470,12 @@ allocate_custom_egl_image_external (CoglTexture2D *tex_2d,
 {
   CoglTexture *tex = COGL_TEXTURE (tex_2d);
   CoglContext *ctx = tex->context;
-  CoglPixelFormat internal_format = loader->src.egl_image_external.format;
+  CoglPixelFormat external_format;
+  CoglPixelFormat internal_format;
+
+  external_format = loader->src.egl_image_external.format;
+  internal_format = _cogl_texture_determine_internal_format (tex,
+                                                             external_format);
 
   _cogl_gl_util_clear_gl_errors (ctx);
 
@@ -854,13 +859,22 @@ _cogl_texture_2d_gl_get_data (CoglTexture2D *tex_2d,
                                                     width,
                                                     bpp);
 
-  _cogl_bind_gl_texture_transient (GL_TEXTURE_2D,
+  _cogl_bind_gl_texture_transient (tex_2d->gl_target,
                                    tex_2d->gl_texture,
                                    tex_2d->is_foreign);
 
   ctx->texture_driver->gl_get_tex_image (ctx,
-                                         GL_TEXTURE_2D,
+                                         tex_2d->gl_target,
                                          gl_format,
                                          gl_type,
                                          data);
 }
+
+CoglBool
+_cogl_texture_2d_gl_is_get_data_supported (CoglTexture2D *tex_2d)
+{
+  if (tex_2d->gl_target == GL_TEXTURE_EXTERNAL_OES)
+    return FALSE;
+  else
+    return TRUE;
+}
diff --git a/cogl/cogl/driver/gl/gl/cogl-driver-gl.c b/cogl/cogl/driver/gl/gl/cogl-driver-gl.c
index 178262ac0..9247e4e78 100644
--- a/cogl/cogl/driver/gl/gl/cogl-driver-gl.c
+++ b/cogl/cogl/driver/gl/gl/cogl-driver-gl.c
@@ -714,6 +714,7 @@ _cogl_driver_gl =
     _cogl_texture_2d_gl_generate_mipmap,
     _cogl_texture_2d_gl_copy_from_bitmap,
     _cogl_texture_2d_gl_get_data,
+    _cogl_texture_2d_gl_is_get_data_supported,
     _cogl_gl_flush_attributes_state,
     _cogl_clip_stack_gl_flush,
     _cogl_buffer_gl_create,
diff --git a/cogl/cogl/driver/gl/gles/cogl-driver-gles.c b/cogl/cogl/driver/gl/gles/cogl-driver-gles.c
index 521f6ef3d..14f9b282c 100644
--- a/cogl/cogl/driver/gl/gles/cogl-driver-gles.c
+++ b/cogl/cogl/driver/gl/gles/cogl-driver-gles.c
@@ -493,6 +493,7 @@ _cogl_driver_gles =
     _cogl_texture_2d_gl_generate_mipmap,
     _cogl_texture_2d_gl_copy_from_bitmap,
     NULL, /* texture_2d_get_data */
+    NULL, /* texture_2d_is_get_data_supported */
     _cogl_gl_flush_attributes_state,
     _cogl_clip_stack_gl_flush,
     _cogl_buffer_gl_create,
diff --git a/cogl/cogl/driver/nop/cogl-driver-nop.c b/cogl/cogl/driver/nop/cogl-driver-nop.c
index 6e04e7164..8424c64ef 100644
--- a/cogl/cogl/driver/nop/cogl-driver-nop.c
+++ b/cogl/cogl/driver/nop/cogl-driver-nop.c
@@ -82,6 +82,7 @@ _cogl_driver_nop =
     _cogl_texture_2d_nop_generate_mipmap,
     _cogl_texture_2d_nop_copy_from_bitmap,
     NULL, /* texture_2d_get_data */
+    NULL, /* texture_2d_is_get_data_supported */
     _cogl_nop_flush_attributes_state,
     _cogl_clip_stack_nop_flush,
   };
diff --git a/cogl/cogl/winsys/cogl-texture-pixmap-x11.c b/cogl/cogl/winsys/cogl-texture-pixmap-x11.c
index d03040c24..3bb057f4a 100644
--- a/cogl/cogl/winsys/cogl-texture-pixmap-x11.c
+++ b/cogl/cogl/winsys/cogl-texture-pixmap-x11.c
@@ -1180,5 +1180,6 @@ cogl_texture_pixmap_x11_vtable =
     _cogl_texture_pixmap_x11_get_gl_format,
     _cogl_texture_pixmap_x11_get_type,
     NULL, /* is_foreign */
-    NULL /* set_auto_mipmap */
+    NULL, /* set_auto_mipmap */
+    NULL  /* is_get_data_supported */
   };
diff --git a/src/compositor/clutter-utils.c b/src/compositor/clutter-utils.c
index fb74732ce..6591ee2d3 100644
--- a/src/compositor/clutter-utils.c
+++ b/src/compositor/clutter-utils.c
@@ -143,7 +143,8 @@ meta_actor_is_untransformed (ClutterActor *actor,
  * transform.
  */
 gboolean
-meta_actor_painting_untransformed (int              paint_width,
+meta_actor_painting_untransformed (CoglFramebuffer *fb,
+                                   int              paint_width,
                                    int              paint_height,
                                    int             *x_origin,
                                    int             *y_origin)
@@ -153,8 +154,8 @@ meta_actor_painting_untransformed (int              paint_width,
   float viewport[4];
   int i;
 
-  cogl_get_modelview_matrix (&modelview);
-  cogl_get_projection_matrix (&projection);
+  cogl_framebuffer_get_modelview_matrix (fb, &modelview);
+  cogl_framebuffer_get_projection_matrix (fb, &projection);
 
   cogl_matrix_multiply (&modelview_projection,
                         &projection,
@@ -173,7 +174,7 @@ meta_actor_painting_untransformed (int              paint_width,
   vertices[3].y = paint_height;
   vertices[3].z = 0;
 
-  cogl_get_viewport (viewport);
+  cogl_framebuffer_get_viewport4fv (fb, viewport);
 
   for (i = 0; i < 4; i++)
     {
diff --git a/src/compositor/clutter-utils.h b/src/compositor/clutter-utils.h
index 36a5925cf..b96733e4a 100644
--- a/src/compositor/clutter-utils.h
+++ b/src/compositor/clutter-utils.h
@@ -31,9 +31,10 @@ gboolean meta_actor_is_untransformed (ClutterActor *actor,
                                       int          *x_origin,
                                       int          *y_origin);
 
-gboolean meta_actor_painting_untransformed (int         paint_width,
-                                            int         paint_height,
-                                            int        *x_origin,
-                                            int        *y_origin);
+gboolean meta_actor_painting_untransformed (CoglFramebuffer *fb,
+                                            int              paint_width,
+                                            int              paint_height,
+                                            int             *x_origin,
+                                            int             *y_origin);
 
 #endif /* __META_CLUTTER_UTILS_H__ */
diff --git a/src/compositor/meta-background-actor.c b/src/compositor/meta-background-actor.c
index 197a62c0f..c4c0f9561 100644
--- a/src/compositor/meta-background-actor.c
+++ b/src/compositor/meta-background-actor.c
@@ -325,6 +325,7 @@ setup_pipeline (MetaBackgroundActor   *self,
   PipelineFlags pipeline_flags = 0;
   guint8 opacity;
   float color_component;
+  CoglFramebuffer *fb;
   CoglPipelineFilter filter;
 
   opacity = clutter_actor_get_paint_opacity (CLUTTER_ACTOR (self));
@@ -417,8 +418,12 @@ setup_pipeline (MetaBackgroundActor   *self,
                              color_component,
                              opacity / 255.);
 
+  fb = cogl_get_draw_framebuffer ();
   if (!priv->force_bilinear &&
-      meta_actor_painting_untransformed (actor_pixel_rect->width, actor_pixel_rect->height, NULL, NULL))
+      meta_actor_painting_untransformed (fb,
+                                         actor_pixel_rect->width,
+                                         actor_pixel_rect->height,
+                                         NULL, NULL))
     filter = COGL_PIPELINE_FILTER_NEAREST;
   else
     filter = COGL_PIPELINE_FILTER_LINEAR;
diff --git a/src/compositor/meta-shaped-texture.c b/src/compositor/meta-shaped-texture.c
index 98346c6ae..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"
 
@@ -373,47 +374,18 @@ set_cogl_texture (MetaShapedTexture *stex,
 }
 
 static void
-meta_shaped_texture_paint (ClutterActor *actor)
+do_paint (MetaShapedTexture *stex,
+          CoglFramebuffer   *fb,
+          CoglTexture       *paint_tex,
+          cairo_region_t    *clip_region)
 {
-  MetaShapedTexture *stex = (MetaShapedTexture *) actor;
   MetaShapedTexturePrivate *priv = stex->priv;
   guint tex_width, tex_height;
   guchar opacity;
   CoglContext *ctx;
-  CoglFramebuffer *fb;
-  CoglTexture *paint_tex;
   ClutterActorBox alloc;
   CoglPipelineFilter filter;
 
-  if (priv->clip_region && cairo_region_is_empty (priv->clip_region))
-    return;
-
-  if (!CLUTTER_ACTOR_IS_REALIZED (CLUTTER_ACTOR (stex)))
-    clutter_actor_realize (CLUTTER_ACTOR (stex));
-
-  /* The GL EXT_texture_from_pixmap extension does allow for it to be
-   * used together with SGIS_generate_mipmap, however this is very
-   * rarely supported. Also, even when it is supported there
-   * are distinct performance implications from:
-   *
-   *  - Updating mipmaps that we don't need
-   *  - Having to reallocate pixmaps on the server into larger buffers
-   *
-   * So, we just unconditionally use our mipmap emulation code. If we
-   * wanted to use SGIS_generate_mipmap, we'd have to  query COGL to
-   * see if it was supported (no API currently), and then if and only
-   * if that was the case, set the clutter texture quality to HIGH.
-   * Setting the texture quality to high without SGIS_generate_mipmap
-   * support for TFP textures will result in fallbacks to XGetImage.
-   */
-  if (priv->create_mipmaps)
-    paint_tex = meta_texture_tower_get_paint_texture (priv->paint_tower);
-  else
-    paint_tex = COGL_TEXTURE (priv->texture);
-
-  if (paint_tex == NULL)
-    return;
-
   tex_width = priv->tex_width;
   tex_height = priv->tex_height;
 
@@ -428,14 +400,15 @@ meta_shaped_texture_paint (ClutterActor *actor)
 
   filter = COGL_PIPELINE_FILTER_LINEAR;
 
-  if (meta_actor_painting_untransformed (tex_width, tex_height, NULL, NULL))
+  if (meta_actor_painting_untransformed (fb,
+                                         tex_width, tex_height,
+                                         NULL, NULL))
     filter = COGL_PIPELINE_FILTER_NEAREST;
 
   ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
-  fb = cogl_get_draw_framebuffer ();
 
-  opacity = clutter_actor_get_paint_opacity (actor);
-  clutter_actor_get_allocation_box (actor, &alloc);
+  opacity = clutter_actor_get_paint_opacity (CLUTTER_ACTOR (stex));
+  clutter_actor_get_allocation_box (CLUTTER_ACTOR (stex), &alloc);
 
   cairo_region_t *blended_region;
   gboolean use_opaque_region = (priv->opaque_region != NULL && opacity == 255);
@@ -573,6 +546,52 @@ meta_shaped_texture_paint (ClutterActor *actor)
     cairo_region_destroy (blended_region);
 }
 
+static void
+meta_shaped_texture_paint (ClutterActor *actor)
+{
+  MetaShapedTexture *stex = META_SHAPED_TEXTURE (actor);
+  MetaShapedTexturePrivate *priv = stex->priv;
+  CoglTexture *paint_tex = NULL;
+  CoglFramebuffer *fb;
+
+  if (!priv->texture)
+    return;
+
+  if (priv->clip_region && cairo_region_is_empty (priv->clip_region))
+    return;
+
+  if (!CLUTTER_ACTOR_IS_REALIZED (CLUTTER_ACTOR (stex)))
+    clutter_actor_realize (CLUTTER_ACTOR (stex));
+
+  /* The GL EXT_texture_from_pixmap extension does allow for it to be
+   * used together with SGIS_generate_mipmap, however this is very
+   * rarely supported. Also, even when it is supported there
+   * are distinct performance implications from:
+   *
+   *  - Updating mipmaps that we don't need
+   *  - Having to reallocate pixmaps on the server into larger buffers
+   *
+   * So, we just unconditionally use our mipmap emulation code. If we
+   * wanted to use SGIS_generate_mipmap, we'd have to  query COGL to
+   * see if it was supported (no API currently), and then if and only
+   * if that was the case, set the clutter texture quality to HIGH.
+   * Setting the texture quality to high without SGIS_generate_mipmap
+   * support for TFP textures will result in fallbacks to XGetImage.
+   */
+  if (priv->create_mipmaps)
+    paint_tex = meta_texture_tower_get_paint_texture (priv->paint_tower);
+
+  if (!paint_tex)
+    paint_tex = COGL_TEXTURE (priv->texture);
+
+  if (cogl_texture_get_width (paint_tex) == 0 ||
+      cogl_texture_get_height (paint_tex) == 0)
+    return;
+
+  fb = cogl_get_draw_framebuffer ();
+  do_paint (META_SHAPED_TEXTURE (actor), fb, paint_tex, priv->clip_region);
+}
+
 static void
 meta_shaped_texture_get_preferred_width (ClutterActor *self,
                                          gfloat        for_height,
@@ -888,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
@@ -906,34 +1040,52 @@ cairo_surface_t *
 meta_shaped_texture_get_image (MetaShapedTexture     *stex,
                                cairo_rectangle_int_t *clip)
 {
+  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);
 
-  texture = COGL_TEXTURE (stex->priv->texture);
+  texture = COGL_TEXTURE (priv->texture);
 
   if (texture == NULL)
     return NULL;
 
-  texture_rect.width = cogl_texture_get_width (texture);
-  texture_rect.height = cogl_texture_get_height (texture);
+  if (priv->tex_width == 0 || priv->tex_height == 0)
+    return NULL;
 
   if (clip != NULL)
     {
-      /* GdkRectangle is just a typedef of cairo_rectangle_int_t,
-       * so we can use the gdk_rectangle_* APIs on these. */
-      if (!gdk_rectangle_intersect (&texture_rect, clip, clip))
+      double tex_scale;
+      cairo_rectangle_int_t tex_rect;
+
+      transformed_clip = alloca (sizeof (cairo_rectangle_int_t));
+      *transformed_clip = *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 (clip != 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,
-                                                 clip->x,
-                                                 clip->y,
-                                                 clip->width,
-                                                 clip->height);
+                                                 transformed_clip->x,
+                                                 transformed_clip->y,
+                                                 transformed_clip->width,
+                                                 transformed_clip->height);
 
   surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
                                         cogl_texture_get_width (texture),
@@ -945,21 +1097,22 @@ meta_shaped_texture_get_image (MetaShapedTexture     *stex,
 
   cairo_surface_mark_dirty (surface);
 
-  if (clip != NULL)
+  if (transformed_clip)
     cogl_object_unref (texture);
 
-  mask_texture = stex->priv->mask_texture;
+  mask_texture = priv->mask_texture;
   if (mask_texture != NULL)
     {
       cairo_t *cr;
       cairo_surface_t *mask_surface;
 
-      if (clip != NULL)
-        mask_texture = cogl_texture_new_from_sub_texture (mask_texture,
-                                                          clip->x,
-                                                          clip->y,
-                                                          clip->width,
-                                                          clip->height);
+      if (transformed_clip)
+        mask_texture =
+          cogl_texture_new_from_sub_texture (mask_texture,
+                                             transformed_clip->x,
+                                             transformed_clip->y,
+                                             transformed_clip->width,
+                                             transformed_clip->height);
 
       mask_surface = cairo_image_surface_create (CAIRO_FORMAT_A8,
                                                  cogl_texture_get_width (mask_texture),
@@ -979,7 +1132,7 @@ meta_shaped_texture_get_image (MetaShapedTexture     *stex,
 
       cairo_surface_destroy (mask_surface);
 
-      if (clip != NULL)
+      if (transformed_clip)
         cogl_object_unref (mask_texture);
     }
 
diff --git a/src/compositor/meta-window-group.c b/src/compositor/meta-window-group.c
index 665adee77..d41c00783 100644
--- a/src/compositor/meta-window-group.c
+++ b/src/compositor/meta-window-group.c
@@ -81,7 +81,11 @@ meta_window_group_paint (ClutterActor *actor)
    */
   if (clutter_actor_is_in_clone_paint (actor))
     {
-      if (!meta_actor_painting_untransformed (screen_width,
+      CoglFramebuffer *fb;
+
+      fb = cogl_get_draw_framebuffer ();
+      if (!meta_actor_painting_untransformed (fb,
+                                              screen_width,
                                               screen_height,
                                               &paint_x_origin,
                                               &paint_y_origin) ||
diff --git a/src/core/boxes-private.h b/src/core/boxes-private.h
index bf019b4d6..793f39527 100644
--- a/src/core/boxes-private.h
+++ b/src/core/boxes-private.h
@@ -38,6 +38,12 @@ typedef enum
   FIXED_DIRECTION_Y    = 1 << 1,
 } FixedDirections;
 
+typedef enum _MetaRoundingStrategy
+{
+  META_ROUNDING_STRATEGY_SHRINK,
+  META_ROUNDING_STRATEGY_GROW,
+} MetaRoundingStrategy;
+
 /* Output functions -- note that the output buffer had better be big enough:
  *   rect_to_string:   RECT_LENGTH
  *   region_to_string: (RECT_LENGTH+strlen(separator_string)) *
@@ -218,6 +224,10 @@ GList* meta_rectangle_find_nonintersected_monitor_edges (
 gboolean meta_rectangle_is_adjecent_to (MetaRectangle *rect,
                                         MetaRectangle *other);
 
+void meta_rectangle_scale_double (MetaRectangle        *rect,
+                                  double                scale,
+                                  MetaRoundingStrategy  rounding_strategy);
+
 static inline ClutterRect
 meta_rectangle_to_clutter_rect (MetaRectangle *rect)
 {
diff --git a/src/core/boxes.c b/src/core/boxes.c
index 35e9ac3cd..0854ecf94 100644
--- a/src/core/boxes.c
+++ b/src/core/boxes.c
@@ -2036,3 +2036,25 @@ meta_rectangle_is_adjecent_to (MetaRectangle *rect,
   else
     return FALSE;
 }
+
+void
+meta_rectangle_scale_double (MetaRectangle        *rect,
+                             double                scale,
+                             MetaRoundingStrategy  rounding_strategy)
+{
+  switch (rounding_strategy)
+    {
+    case META_ROUNDING_STRATEGY_SHRINK:
+      rect->x = (int) ceil (rect->x * scale);
+      rect->y = (int) ceil (rect->y * scale);
+      rect->width = (int) floor (rect->width * scale);
+      rect->height = (int) floor (rect->height * scale);
+      break;
+    case META_ROUNDING_STRATEGY_GROW:
+      rect->x = (int) floor (rect->x * scale);
+      rect->y = (int) floor (rect->y * scale);
+      rect->width = (int) ceil (rect->width * scale);
+      rect->height = (int) ceil (rect->height * scale);
+      break;
+    }
+}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]