[mutter] shaped-texture: Add support for texture transform



commit 1467b6b02a73bca768511cac96301ce50e106a1c
Author: Robert Mader <robert mader posteo de>
Date:   Sat Nov 24 18:27:29 2018 +0100

    shaped-texture: Add support for texture transform
    
    This adds the necessary bits to support Wayland buffer transforms.
    The main part here is to properly setup the Cogl pipeline
    and to recalculate the size of the painted area accordingly,
    so culling etc. still works.
    
    The choosen approach additionally lays groundwork for Wayland
    wp_viewporter support.
    
    https://gitlab.gnome.org/GNOME/mutter/merge_requests/322

 src/compositor/meta-shaped-texture-private.h |   3 +
 src/compositor/meta-shaped-texture.c         | 190 +++++++++++++++++++++------
 src/compositor/meta-surface-actor.c          |   9 ++
 src/compositor/meta-surface-actor.h          |   3 +
 4 files changed, 168 insertions(+), 37 deletions(-)
---
diff --git a/src/compositor/meta-shaped-texture-private.h b/src/compositor/meta-shaped-texture-private.h
index 284f43e36..44816a14d 100644
--- a/src/compositor/meta-shaped-texture-private.h
+++ b/src/compositor/meta-shaped-texture-private.h
@@ -27,6 +27,7 @@
 #ifndef __META_SHAPED_TEXTURE_PRIVATE_H__
 #define __META_SHAPED_TEXTURE_PRIVATE_H__
 
+#include "backends/meta-monitor-manager-private.h"
 #include "meta/meta-shaped-texture.h"
 
 ClutterActor *meta_shaped_texture_new (void);
@@ -41,5 +42,7 @@ void meta_shaped_texture_set_fallback_size (MetaShapedTexture *stex,
                                             int                fallback_height);
 gboolean meta_shaped_texture_is_obscured (MetaShapedTexture *self);
 cairo_region_t * meta_shaped_texture_get_opaque_region (MetaShapedTexture *stex);
+void meta_shaped_texture_set_transform (MetaShapedTexture    *stex,
+                                        MetaMonitorTransform  transform);
 
 #endif
diff --git a/src/compositor/meta-shaped-texture.c b/src/compositor/meta-shaped-texture.c
index 919e7a9b5..3a7710301 100644
--- a/src/compositor/meta-shaped-texture.c
+++ b/src/compositor/meta-shaped-texture.c
@@ -103,8 +103,12 @@ struct _MetaShapedTexturePrivate
   cairo_region_t *clip_region;
   cairo_region_t *unobscured_region;
 
+  gboolean size_invalid;
+  MetaMonitorTransform transform;
+
   int tex_width, tex_height;
   int fallback_width, fallback_height;
+  int dst_width, dst_height;
 
   gint64 prev_invalidation, last_invalidation;
   guint fast_updates;
@@ -139,6 +143,14 @@ meta_shaped_texture_class_init (MetaShapedTextureClass *klass)
                                         G_TYPE_NONE, 0);
 }
 
+static void
+invalidate_size (MetaShapedTexture *stex)
+{
+  MetaShapedTexturePrivate *priv = stex->priv;
+
+  priv->size_invalid = TRUE;
+}
+
 static void
 meta_shaped_texture_init (MetaShapedTexture *self)
 {
@@ -152,6 +164,68 @@ meta_shaped_texture_init (MetaShapedTexture *self)
   priv->mask_texture = NULL;
   priv->create_mipmaps = TRUE;
   priv->is_y_inverted = TRUE;
+  priv->transform = META_MONITOR_TRANSFORM_NORMAL;
+
+  g_signal_connect (self,
+                    "notify::scale-x",
+                    G_CALLBACK (invalidate_size),
+                    self);
+}
+
+static void
+update_size (MetaShapedTexture *stex)
+{
+  MetaShapedTexturePrivate *priv = stex->priv;
+  int dst_width;
+  int dst_height;
+
+  if (meta_monitor_transform_is_rotated (priv->transform))
+    {
+      if (priv->texture)
+        {
+          dst_width = priv->tex_height;
+          dst_height = priv->tex_width;
+        }
+      else
+        {
+          dst_width = priv->fallback_height;
+          dst_height = priv->fallback_width;
+        }
+    }
+  else
+    {
+      if (priv->texture)
+        {
+          dst_width = priv->tex_width;
+          dst_height = priv->tex_height;
+        }
+      else
+        {
+          dst_width = priv->fallback_width;
+          dst_height = priv->fallback_height;
+        }
+    }
+
+  priv->size_invalid = FALSE;
+
+  if (priv->dst_width != dst_width ||
+      priv->dst_height != dst_height)
+    {
+      priv->dst_width = dst_width;
+      priv->dst_height = dst_height;
+      meta_shaped_texture_set_mask_texture (stex, NULL);
+      clutter_actor_queue_relayout (CLUTTER_ACTOR (stex));
+      g_signal_emit (stex, signals[SIZE_CHANGED], 0);
+    }
+}
+
+static void
+ensure_size_valid (MetaShapedTexture *stex)
+{
+  MetaShapedTexturePrivate *priv = stex->priv;
+
+  if (priv->size_invalid)
+    update_size (stex);
 }
 
 static void
@@ -165,16 +239,9 @@ set_unobscured_region (MetaShapedTexture *self,
     {
       int width, height;
 
-      if (priv->texture)
-        {
-          width = priv->tex_width;
-          height = priv->tex_height;
-        }
-      else
-        {
-          width = priv->fallback_width;
-          height = priv->fallback_height;
-        }
+      ensure_size_valid (self);
+      width = priv->dst_width;
+      height = priv->dst_height;
 
       cairo_rectangle_int_t bounds = { 0, 0, width, height };
       priv->unobscured_region = cairo_region_copy (unobscured_region);
@@ -262,6 +329,45 @@ get_base_pipeline (MetaShapedTexture *stex,
       cogl_pipeline_set_layer_matrix (pipeline, 0, &matrix);
     }
 
+  if (priv->transform != META_MONITOR_TRANSFORM_NORMAL)
+    {
+      CoglMatrix matrix;
+      CoglEuler euler;
+
+      cogl_matrix_init_translation (&matrix, 0.5, 0.5, 0.0);
+      switch (priv->transform)
+        {
+        case META_MONITOR_TRANSFORM_90:
+          cogl_euler_init (&euler, 0.0, 0.0, 90.0);
+          break;
+        case META_MONITOR_TRANSFORM_180:
+          cogl_euler_init (&euler, 0.0, 0.0, 180.0);
+          break;
+        case META_MONITOR_TRANSFORM_270:
+          cogl_euler_init (&euler, 0.0, 0.0, 270.0);
+          break;
+        case META_MONITOR_TRANSFORM_FLIPPED:
+          cogl_euler_init (&euler, 180.0, 0.0, 0.0);
+          break;
+        case META_MONITOR_TRANSFORM_FLIPPED_90:
+          cogl_euler_init (&euler, 0.0, 180.0, 90.0);
+          break;
+        case META_MONITOR_TRANSFORM_FLIPPED_180:
+          cogl_euler_init (&euler, 180.0, 0.0, 180.0);
+          break;
+        case META_MONITOR_TRANSFORM_FLIPPED_270:
+          cogl_euler_init (&euler, 0.0, 180.0, 270.0);
+          break;
+        case META_MONITOR_TRANSFORM_NORMAL:
+          g_assert_not_reached ();
+        }
+      cogl_matrix_rotate_euler (&matrix, &euler);
+      cogl_matrix_translate (&matrix, -0.5, -0.5, 0.0);
+
+      cogl_pipeline_set_layer_matrix (pipeline, 0, &matrix);
+      cogl_pipeline_set_layer_matrix (pipeline, 1, &matrix);
+    }
+
   if (priv->snippet)
     cogl_pipeline_add_layer_snippet (pipeline, 0, priv->snippet);
 
@@ -382,9 +488,7 @@ set_cogl_texture (MetaShapedTexture *stex,
     {
       priv->tex_width = width;
       priv->tex_height = height;
-      meta_shaped_texture_set_mask_texture (stex, NULL);
-      clutter_actor_queue_relayout (CLUTTER_ACTOR (stex));
-      g_signal_emit (stex, signals[SIZE_CHANGED], 0);
+      update_size (stex);
     }
 
   /* NB: We don't queue a redraw of the actor here because we don't
@@ -417,7 +521,7 @@ meta_shaped_texture_paint (ClutterActor *actor)
   MetaShapedTexture *stex = (MetaShapedTexture *) actor;
   MetaShapedTexturePrivate *priv = stex->priv;
   double tex_scale;
-  int tex_width, tex_height;
+  int dst_width, dst_height;
   cairo_rectangle_int_t tex_rect;
   guchar opacity;
   gboolean use_opaque_region;
@@ -482,13 +586,14 @@ meta_shaped_texture_paint (ClutterActor *actor)
     }
 
   clutter_actor_get_scale (actor, &tex_scale, NULL);
-  tex_width = priv->tex_width;
-  tex_height = priv->tex_height;
+  ensure_size_valid (stex);
+  dst_width = priv->dst_width;
+  dst_height = priv->dst_height;
 
-  if (tex_width == 0 || tex_height == 0) /* no contents yet */
+  if (dst_width == 0 || dst_height == 0) /* no contents yet */
     return;
 
-  tex_rect = (cairo_rectangle_int_t) { 0, 0, tex_width, tex_height };
+  tex_rect = (cairo_rectangle_int_t) { 0, 0, dst_width, dst_height };
 
   /* Use nearest-pixel interpolation if the texture is unscaled. This
    * improves performance, especially with software rendering.
@@ -496,7 +601,7 @@ 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 (dst_width, dst_height, NULL, NULL))
     filter = COGL_PIPELINE_FILTER_NEAREST;
 
   ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
@@ -670,18 +775,15 @@ meta_shaped_texture_get_preferred_width (ClutterActor *self,
                                          gfloat       *min_width_p,
                                          gfloat       *natural_width_p)
 {
-  MetaShapedTexturePrivate *priv = META_SHAPED_TEXTURE (self)->priv;
-  int width;
+  MetaShapedTexture *stex = META_SHAPED_TEXTURE (self);
+  MetaShapedTexturePrivate *priv = stex->priv;
 
-  if (priv->texture)
-    width = priv->tex_width;
-  else
-    width = priv->fallback_width;
+  ensure_size_valid (stex);
 
   if (min_width_p)
-    *min_width_p = width;
+    *min_width_p = priv->dst_width;
   if (natural_width_p)
-    *natural_width_p = width;
+    *natural_width_p = priv->dst_width;
 }
 
 static void
@@ -690,18 +792,15 @@ meta_shaped_texture_get_preferred_height (ClutterActor *self,
                                           gfloat       *min_height_p,
                                           gfloat       *natural_height_p)
 {
-  MetaShapedTexturePrivate *priv = META_SHAPED_TEXTURE (self)->priv;
-  int height;
+  MetaShapedTexture *stex = META_SHAPED_TEXTURE (self);
+  MetaShapedTexturePrivate *priv = stex->priv;
 
-  if (priv->texture)
-    height = priv->tex_height;
-  else
-    height = priv->fallback_height;
+  ensure_size_valid (stex);
 
   if (min_height_p)
-    *min_height_p = height;
+    *min_height_p = priv->dst_height;
   if (natural_height_p)
-    *natural_height_p = height;
+    *natural_height_p = priv->dst_height;
 }
 
 static cairo_region_t *
@@ -958,6 +1057,21 @@ meta_shaped_texture_get_opaque_region (MetaShapedTexture *stex)
   return priv->opaque_region;
 }
 
+void
+meta_shaped_texture_set_transform (MetaShapedTexture    *stex,
+                                   MetaMonitorTransform  transform)
+{
+  MetaShapedTexturePrivate *priv = stex->priv;
+
+  if (priv->transform == transform)
+    return;
+
+  priv->transform = transform;
+
+  meta_shaped_texture_reset_pipelines (stex);
+  invalidate_size (stex);
+}
+
 /**
  * meta_shaped_texture_get_image:
  * @stex: A #MetaShapedTexture
@@ -1057,14 +1171,16 @@ meta_shaped_texture_get_image (MetaShapedTexture     *stex,
 }
 
 void
-meta_shaped_texture_set_fallback_size (MetaShapedTexture *self,
+meta_shaped_texture_set_fallback_size (MetaShapedTexture *stex,
                                        int                fallback_width,
                                        int                fallback_height)
 {
-  MetaShapedTexturePrivate *priv = self->priv;
+  MetaShapedTexturePrivate *priv = stex->priv;
 
   priv->fallback_width = fallback_width;
   priv->fallback_height = fallback_height;
+
+  invalidate_size (stex);
 }
 
 static void
diff --git a/src/compositor/meta-surface-actor.c b/src/compositor/meta-surface-actor.c
index 256215373..823c1ac12 100644
--- a/src/compositor/meta-surface-actor.c
+++ b/src/compositor/meta-surface-actor.c
@@ -385,3 +385,12 @@ meta_surface_actor_get_window (MetaSurfaceActor *self)
 {
   return META_SURFACE_ACTOR_GET_CLASS (self)->get_window (self);
 }
+
+void
+meta_surface_actor_set_transform (MetaSurfaceActor     *self,
+                                  MetaMonitorTransform  transform)
+{
+  MetaSurfaceActorPrivate *priv = self->priv;
+
+  meta_shaped_texture_set_transform (priv->texture, transform);
+}
diff --git a/src/compositor/meta-surface-actor.h b/src/compositor/meta-surface-actor.h
index 6a2740023..102b67083 100644
--- a/src/compositor/meta-surface-actor.h
+++ b/src/compositor/meta-surface-actor.h
@@ -5,6 +5,7 @@
 
 #include "config.h"
 
+#include "backends/meta-backend-types.h"
 #include "meta/meta-shaped-texture.h"
 #include "meta/window.h"
 
@@ -76,6 +77,8 @@ void meta_surface_actor_set_unredirected (MetaSurfaceActor *actor,
                                           gboolean          unredirected);
 gboolean meta_surface_actor_is_unredirected (MetaSurfaceActor *actor);
 
+void meta_surface_actor_set_transform (MetaSurfaceActor     *self,
+                                       MetaMonitorTransform  transform);
 G_END_DECLS
 
 #endif /* META_SURFACE_ACTOR_PRIVATE_H */


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