[mutter] shaped-texture: Add support for viewports



commit edfe5cc3b7533a663dae6fee43938ae40b289387
Author: Robert Mader <robert mader posteo de>
Date:   Fri Nov 30 15:34:00 2018 +0100

    shaped-texture: Add support for viewports
    
    This implements the viewporter protocol which offers a cropping and scaling
    capabilities to wayland clients.
    
    There are several use cases for this, for example video players and games,
    both as a convenience function and as potential performance optimization when
    paired with hardware overlays etc.
    
    https://gitlab.gnome.org/GNOME/mutter/merge_requests/323

 src/compositor/meta-shaped-texture-private.h |   7 +
 src/compositor/meta-shaped-texture.c         | 234 +++++++++++++++++++++++----
 src/compositor/meta-surface-actor.c          |  41 +++++
 src/compositor/meta-surface-actor.h          |   7 +
 4 files changed, 262 insertions(+), 27 deletions(-)
---
diff --git a/src/compositor/meta-shaped-texture-private.h b/src/compositor/meta-shaped-texture-private.h
index 44816a14d..a86a2bff0 100644
--- a/src/compositor/meta-shaped-texture-private.h
+++ b/src/compositor/meta-shaped-texture-private.h
@@ -44,5 +44,12 @@ 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);
+void meta_shaped_texture_set_viewport_src_rect (MetaShapedTexture *stex,
+                                                ClutterRect       *src_rect);
+void meta_shaped_texture_reset_viewport_src_rect (MetaShapedTexture *stex);
+void meta_shaped_texture_set_viewport_dst_size (MetaShapedTexture *stex,
+                                                int                dst_width,
+                                                int                dst_height);
+void meta_shaped_texture_reset_viewport_dst_size (MetaShapedTexture *stex);
 
 #endif
diff --git a/src/compositor/meta-shaped-texture.c b/src/compositor/meta-shaped-texture.c
index 9f96d6718..b04ae89c2 100644
--- a/src/compositor/meta-shaped-texture.c
+++ b/src/compositor/meta-shaped-texture.c
@@ -32,6 +32,7 @@
 #include "core/boxes-private.h"
 
 #include <gdk/gdk.h>
+#include <math.h>
 
 #include "cogl/cogl.h"
 #include "compositor/clutter-utils.h"
@@ -106,6 +107,11 @@ struct _MetaShapedTexture
 
   gboolean size_invalid;
   MetaMonitorTransform transform;
+  gboolean has_viewport_src_rect;
+  ClutterRect viewport_src_rect;
+  gboolean has_viewport_dst_size;
+  int viewport_dst_width;
+  int viewport_dst_height;
 
   int tex_width, tex_height;
   int fallback_width, fallback_height;
@@ -169,33 +175,53 @@ meta_shaped_texture_init (MetaShapedTexture *stex)
 static void
 update_size (MetaShapedTexture *stex)
 {
+  ClutterActor *actor = CLUTTER_ACTOR (stex);
   int dst_width;
   int dst_height;
 
-  if (meta_monitor_transform_is_rotated (stex->transform))
+  if (stex->has_viewport_dst_size)
     {
-      if (stex->texture)
-        {
-          dst_width = stex->tex_height;
-          dst_height = stex->tex_width;
-        }
-      else
-        {
-          dst_width = stex->fallback_height;
-          dst_height = stex->fallback_width;
-        }
+      double tex_scale;
+
+      clutter_actor_get_scale (actor, &tex_scale, NULL);
+      dst_width = ceil (stex->viewport_dst_width / tex_scale);
+      dst_height = ceil (stex->viewport_dst_height / tex_scale);
+    }
+  else if (stex->has_viewport_src_rect)
+    {
+      double tex_scale;
+
+      clutter_actor_get_scale (actor, &tex_scale, NULL);
+      dst_width = ceil (stex->viewport_src_rect.size.width / tex_scale);
+      dst_height = ceil (stex->viewport_src_rect.size.height / tex_scale);
     }
   else
     {
-      if (stex->texture)
+      if (meta_monitor_transform_is_rotated (stex->transform))
         {
-          dst_width = stex->tex_width;
-          dst_height = stex->tex_height;
+          if (stex->texture)
+            {
+              dst_width = stex->tex_height;
+              dst_height = stex->tex_width;
+            }
+          else
+            {
+              dst_width = stex->fallback_height;
+              dst_height = stex->fallback_width;
+            }
         }
       else
         {
-          dst_width = stex->fallback_width;
-          dst_height = stex->fallback_height;
+          if (stex->texture)
+            {
+              dst_width = stex->tex_width;
+              dst_height = stex->tex_height;
+            }
+          else
+            {
+              dst_width = stex->fallback_width;
+              dst_height = stex->fallback_height;
+            }
         }
     }
 
@@ -408,23 +434,66 @@ get_unblended_pipeline (MetaShapedTexture *stex,
 }
 
 static void
-paint_clipped_rectangle (CoglFramebuffer       *fb,
+paint_clipped_rectangle (MetaShapedTexture     *stex,
+                         CoglFramebuffer       *fb,
                          CoglPipeline          *pipeline,
                          cairo_rectangle_int_t *rect,
                          ClutterActorBox       *alloc)
 {
   float coords[8];
   float x1, y1, x2, y2;
+  float alloc_width;
+  float alloc_height;
 
   x1 = rect->x;
   y1 = rect->y;
   x2 = rect->x + rect->width;
   y2 = rect->y + rect->height;
+  alloc_width = alloc->x2 - alloc->x1;
+  alloc_height = alloc->y2 - alloc->y1;
+
+  if (stex->has_viewport_src_rect)
+    {
+      double tex_scale;
+      float src_x;
+      float src_y;
+      float src_width;
+      float src_height;
+
+      clutter_actor_get_scale (CLUTTER_ACTOR (stex), &tex_scale, NULL);
+
+      src_x = stex->viewport_src_rect.origin.x / tex_scale;
+      src_y = stex->viewport_src_rect.origin.y / tex_scale;
+      src_width = stex->viewport_src_rect.size.width / tex_scale;
+      src_height = stex->viewport_src_rect.size.height / tex_scale;
 
-  coords[0] = rect->x / (alloc->x2 - alloc->x1);
-  coords[1] = rect->y / (alloc->y2 - alloc->y1);
-  coords[2] = (rect->x + rect->width) / (alloc->x2 - alloc->x1);
-  coords[3] = (rect->y + rect->height) / (alloc->y2 - alloc->y1);
+      coords[0] = rect->x * src_width / alloc_width + src_x;
+      coords[1] = rect->y * src_height / alloc_height + src_y;
+      coords[2] = rect->width * src_width / alloc_width + coords[0];
+      coords[3] = rect->height * src_height / alloc_height + coords[1];
+
+      if (meta_monitor_transform_is_rotated (stex->transform))
+        {
+          coords[0] /= stex->tex_height;
+          coords[1] /= stex->tex_width;
+          coords[2] /= stex->tex_height;
+          coords[3] /= stex->tex_width;
+        }
+      else
+        {
+          coords[0] /= stex->tex_width;
+          coords[1] /= stex->tex_height;
+          coords[2] /= stex->tex_width;
+          coords[3] /= stex->tex_height;
+        }
+    }
+  else
+    {
+      coords[0] = rect->x / alloc_width;
+      coords[1] = rect->y / alloc_height;
+      coords[2] = (rect->x + rect->width) / alloc_width;
+      coords[3] = (rect->y + rect->height) / alloc_height;
+    }
 
   coords[4] = coords[0];
   coords[5] = coords[1];
@@ -624,7 +693,11 @@ do_paint (MetaShapedTexture *stex,
             {
               cairo_rectangle_int_t rect;
               cairo_region_get_rectangle (region, i, &rect);
-              paint_clipped_rectangle (fb, opaque_pipeline, &rect, &alloc);
+              paint_clipped_rectangle (stex,
+                                       fb,
+                                       opaque_pipeline,
+                                       &rect,
+                                       &alloc);
             }
         }
 
@@ -677,16 +750,21 @@ do_paint (MetaShapedTexture *stex,
               if (!gdk_rectangle_intersect (&tex_rect, &rect, &rect))
                 continue;
 
-              paint_clipped_rectangle (fb, blended_pipeline, &rect, &alloc);
+              paint_clipped_rectangle (stex,
+                                       fb,
+                                       blended_pipeline,
+                                       &rect,
+                                       &alloc);
             }
         }
       else
         {
           /* 3) blended_tex_region is NULL. Do a full paint. */
-          cogl_framebuffer_draw_rectangle (fb, blended_pipeline,
-                                           0, 0,
-                                           alloc.x2 - alloc.x1,
-                                           alloc.y2 - alloc.y1);
+          paint_clipped_rectangle (stex,
+                                   fb,
+                                   blended_pipeline,
+                                   &tex_rect,
+                                   &alloc);
         }
     }
 
@@ -909,6 +987,59 @@ meta_shaped_texture_update_area (MetaShapedTexture *stex,
                             stex->dst_height,
                             &clip);
 
+  if (stex->has_viewport_src_rect || stex->has_viewport_dst_size)
+    {
+      ClutterRect viewport;
+      ClutterRect inverted_viewport;
+      double tex_scale;
+      float dst_width;
+      float dst_height;
+      int inverted_dst_width;
+      int inverted_dst_height;
+
+      clutter_actor_get_scale (CLUTTER_ACTOR (stex), &tex_scale, NULL);
+
+      if (stex->has_viewport_src_rect)
+        {
+          viewport = stex->viewport_src_rect;
+        }
+      else
+        {
+          viewport = (ClutterRect) {
+            .origin.x = 0,
+            .origin.y = 0,
+            .size.width = stex->tex_width * tex_scale,
+            .size.height = stex->tex_height * tex_scale
+          };
+        }
+
+      if (stex->has_viewport_dst_size)
+        {
+          dst_width = (float) stex->viewport_dst_width;
+          dst_height = (float) stex->viewport_dst_height;
+        }
+      else
+        {
+          dst_width = (float) stex->tex_width * tex_scale;
+          dst_height = (float) stex->tex_height * tex_scale;
+        }
+
+      inverted_viewport = (ClutterRect) {
+        .origin.x = -((viewport.origin.x * (dst_width / viewport.size.width)) / tex_scale),
+        .origin.y = -((viewport.origin.y * (dst_height / viewport.size.height)) / tex_scale),
+        .size.width = dst_width,
+        .size.height = dst_height
+      };
+      inverted_dst_width = ceilf (viewport.size.width);
+      inverted_dst_height = ceilf (viewport.size.height);
+
+      meta_rectangle_crop_and_scale (&clip,
+                                     &inverted_viewport,
+                                     inverted_dst_width,
+                                     inverted_dst_height,
+                                     &clip);
+    }
+
   meta_texture_tower_update_area (stex->paint_tower,
                                   clip.x,
                                   clip.y,
@@ -1063,12 +1194,61 @@ meta_shaped_texture_set_transform (MetaShapedTexture    *stex,
   invalidate_size (stex);
 }
 
+void
+meta_shaped_texture_set_viewport_src_rect (MetaShapedTexture *stex,
+                                           ClutterRect       *src_rect)
+{
+  if (!stex->has_viewport_src_rect ||
+      stex->viewport_src_rect.origin.x != src_rect->origin.x ||
+      stex->viewport_src_rect.origin.y != src_rect->origin.y ||
+      stex->viewport_src_rect.size.width != src_rect->size.width ||
+      stex->viewport_src_rect.size.height != src_rect->size.height)
+    {
+      stex->has_viewport_src_rect = TRUE;
+      stex->viewport_src_rect = *src_rect;
+      invalidate_size (stex);
+    }
+}
+
+void
+meta_shaped_texture_reset_viewport_src_rect (MetaShapedTexture *stex)
+{
+  stex->has_viewport_src_rect = FALSE;
+  invalidate_size (stex);
+}
+
+void
+meta_shaped_texture_set_viewport_dst_size (MetaShapedTexture *stex,
+                                           int                dst_width,
+                                           int                dst_height)
+{
+  if (!stex->has_viewport_dst_size ||
+      stex->viewport_dst_width != dst_width ||
+      stex->viewport_dst_height != dst_height)
+    {
+      stex->has_viewport_dst_size = TRUE;
+      stex->viewport_dst_width = dst_width;
+      stex->viewport_dst_height = dst_height;
+      invalidate_size (stex);
+    }
+}
+
+void
+meta_shaped_texture_reset_viewport_dst_size (MetaShapedTexture *stex)
+{
+  stex->has_viewport_dst_size = FALSE;
+  invalidate_size (stex);
+}
+
 static gboolean
 should_get_via_offscreen (MetaShapedTexture *stex)
 {
   if (!cogl_texture_is_get_data_supported (stex->texture))
     return TRUE;
 
+  if (stex->has_viewport_src_rect || stex->has_viewport_dst_size)
+    return TRUE;
+
   switch (stex->transform)
     {
     case META_MONITOR_TRANSFORM_90:
diff --git a/src/compositor/meta-surface-actor.c b/src/compositor/meta-surface-actor.c
index 6edf7c22d..fb2776000 100644
--- a/src/compositor/meta-surface-actor.c
+++ b/src/compositor/meta-surface-actor.c
@@ -419,3 +419,44 @@ meta_surface_actor_set_transform (MetaSurfaceActor     *self,
 
   meta_shaped_texture_set_transform (priv->texture, transform);
 }
+
+void
+meta_surface_actor_set_viewport_src_rect (MetaSurfaceActor  *self,
+                                          ClutterRect       *src_rect)
+{
+  MetaSurfaceActorPrivate *priv =
+    meta_surface_actor_get_instance_private (self);
+
+  meta_shaped_texture_set_viewport_src_rect (priv->texture, src_rect);
+}
+
+void
+meta_surface_actor_reset_viewport_src_rect (MetaSurfaceActor *self)
+{
+  MetaSurfaceActorPrivate *priv =
+    meta_surface_actor_get_instance_private (self);
+
+  meta_shaped_texture_reset_viewport_src_rect (priv->texture);
+}
+
+void
+meta_surface_actor_set_viewport_dst_size (MetaSurfaceActor *self,
+                                          int               dst_width,
+                                          int               dst_height)
+{
+  MetaSurfaceActorPrivate *priv =
+    meta_surface_actor_get_instance_private (self);
+
+  meta_shaped_texture_set_viewport_dst_size (priv->texture,
+                                             dst_width,
+                                             dst_height);
+}
+
+void
+meta_surface_actor_reset_viewport_dst_size (MetaSurfaceActor *self)
+{
+  MetaSurfaceActorPrivate *priv =
+    meta_surface_actor_get_instance_private (self);
+
+  meta_shaped_texture_reset_viewport_dst_size (priv->texture);
+}
diff --git a/src/compositor/meta-surface-actor.h b/src/compositor/meta-surface-actor.h
index bf60ac462..1cffcf99c 100644
--- a/src/compositor/meta-surface-actor.h
+++ b/src/compositor/meta-surface-actor.h
@@ -65,6 +65,13 @@ gboolean meta_surface_actor_is_unredirected (MetaSurfaceActor *actor);
 
 void meta_surface_actor_set_transform (MetaSurfaceActor     *self,
                                        MetaMonitorTransform  transform);
+void meta_surface_actor_set_viewport_src_rect (MetaSurfaceActor  *self,
+                                               ClutterRect       *src_rect);
+void meta_surface_actor_reset_viewport_src_rect (MetaSurfaceActor *self);
+void meta_surface_actor_set_viewport_dst_size (MetaSurfaceActor  *self,
+                                               int                dst_width,
+                                               int                dst_height);
+void meta_surface_actor_reset_viewport_dst_size (MetaSurfaceActor *self);
 G_END_DECLS
 
 #endif /* META_SURFACE_ACTOR_PRIVATE_H */


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