[mutter] wayland/surface: Add support for buffer transforms



commit e4de9ed580ba555430a5ef018d3b4c539d20856a
Author: Robert Mader <robert mader posteo de>
Date:   Mon Nov 26 19:40:57 2018 +0100

    wayland/surface: Add support for buffer transforms
    
    This adds the required bits to wayland surfaces and ties them up
    to the compositor parts.
    
    The central part here is to recalculate the surface size accordingly
    and to translate surface damage into buffer damage.
    
    The choosen approach additionally lays groundwork for wp_viewporter
    support, which is closely related in its nature.
    
    A further explanation of buffer transforms from the specification:
    > The purpose of this request is to allow clients to render content
    > according to the output transform, thus permitting the compositor
    > to use certain optimizations even if the display is rotated.
    > Using hardware overlays and scanning out a client buffer for
    > fullscreen surfaces are examples of such optimizations.

 src/wayland/meta-wayland-actor-surface.c |   2 +
 src/wayland/meta-wayland-surface.c       | 141 ++++++++++++++++++++++++-------
 src/wayland/meta-wayland-surface.h       |   5 ++
 3 files changed, 119 insertions(+), 29 deletions(-)
---
diff --git a/src/wayland/meta-wayland-actor-surface.c b/src/wayland/meta-wayland-actor-surface.c
index b69c31f72..56ea66e1e 100644
--- a/src/wayland/meta-wayland-actor-surface.c
+++ b/src/wayland/meta-wayland-actor-surface.c
@@ -205,6 +205,8 @@ meta_wayland_actor_surface_real_sync_actor_state (MetaWaylandActorSurface *actor
       meta_surface_actor_set_opaque_region (surface_actor, NULL);
     }
 
+  meta_surface_actor_set_transform (surface_actor, surface->buffer_transform);
+
   for (l = surface->subsurfaces; l; l = l->next)
     {
       MetaWaylandSurface *subsurface_surface = l->data;
diff --git a/src/wayland/meta-wayland-surface.c b/src/wayland/meta-wayland-surface.c
index d8d561901..297767a0d 100644
--- a/src/wayland/meta-wayland-surface.c
+++ b/src/wayland/meta-wayland-surface.c
@@ -32,7 +32,6 @@
 #include "clutter/wayland/clutter-wayland-compositor.h"
 #include "clutter/wayland/clutter-wayland-surface.h"
 #include "cogl/cogl-wayland-server.h"
-#include "compositor/meta-shaped-texture-private.h"
 #include "compositor/meta-surface-actor-wayland.h"
 #include "compositor/meta-surface-actor.h"
 #include "compositor/meta-window-actor-private.h"
@@ -253,14 +252,47 @@ meta_wayland_surface_assign_role (MetaWaylandSurface *surface,
     }
 }
 
+static int
+get_buffer_width (MetaWaylandSurface *surface)
+{
+  MetaWaylandBuffer *buffer = meta_wayland_surface_get_buffer (surface);
+
+  if (buffer)
+    {
+      CoglTexture *texture = meta_wayland_buffer_get_texture (buffer);
+      return cogl_texture_get_width (texture);
+    }
+  else
+    {
+      return 0;
+    }
+}
+
+static int
+get_buffer_height (MetaWaylandSurface *surface)
+{
+  MetaWaylandBuffer *buffer = meta_wayland_surface_get_buffer (surface);
+
+  if (buffer)
+    {
+      CoglTexture *texture = meta_wayland_buffer_get_texture (buffer);
+      return cogl_texture_get_height (texture);
+    }
+  else
+    {
+      return 0;
+    }
+}
+
 static void
 surface_process_damage (MetaWaylandSurface *surface,
                         cairo_region_t     *surface_region,
                         cairo_region_t     *buffer_region)
 {
-  MetaWaylandBuffer *buffer = surface->buffer_ref.buffer;
+  MetaWaylandBuffer *buffer = meta_wayland_surface_get_buffer (surface);
   cairo_rectangle_int_t surface_rect;
   cairo_region_t *scaled_region;
+  cairo_region_t *transformed_region;
   int i, n_rectangles;
 
   /* If the client destroyed the buffer it attached before committing, but
@@ -282,22 +314,26 @@ surface_process_damage (MetaWaylandSurface *surface,
   /* The damage region must be in the same coordinate space as the buffer,
    * i.e. scaled with surface->scale. */
   scaled_region = meta_region_scale (surface_region, surface->scale);
+  transformed_region = meta_region_transform (scaled_region,
+                                              surface->buffer_transform,
+                                              get_buffer_width (surface),
+                                              get_buffer_height (surface));
 
   /* Now add the buffer damage on top of the scaled damage region, as buffer
    * damage is already in that scale. */
-  cairo_region_union (scaled_region, buffer_region);
+  cairo_region_union (transformed_region, buffer_region);
 
   /* First update the buffer. */
-  meta_wayland_buffer_process_damage (buffer, scaled_region);
+  meta_wayland_buffer_process_damage (buffer, transformed_region);
 
   /* Now damage the actor. The actor expects damage in the unscaled texture
    * coordinate space, i.e. same as the buffer. */
   /* XXX: Should this be a signal / callback on MetaWaylandBuffer instead? */
-  n_rectangles = cairo_region_num_rectangles (scaled_region);
+  n_rectangles = cairo_region_num_rectangles (transformed_region);
   for (i = 0; i < n_rectangles; i++)
     {
       cairo_rectangle_int_t rect;
-      cairo_region_get_rectangle (scaled_region, i, &rect);
+      cairo_region_get_rectangle (transformed_region, i, &rect);
 
       meta_surface_actor_process_damage (meta_wayland_surface_get_actor (surface),
                                          rect.x, rect.y,
@@ -305,6 +341,7 @@ surface_process_damage (MetaWaylandSurface *surface,
     }
 
   cairo_region_destroy (scaled_region);
+  cairo_region_destroy (transformed_region);
 }
 
 void
@@ -400,6 +437,8 @@ pending_state_init (MetaWaylandPendingState *state)
   state->has_new_geometry = FALSE;
   state->has_new_min_size = FALSE;
   state->has_new_max_size = FALSE;
+
+  state->has_new_buffer_transform = FALSE;
 }
 
 static void
@@ -507,6 +546,12 @@ merge_pending_state (MetaWaylandPendingState *from,
   if (from->scale > 0)
     to->scale = from->scale;
 
+  if (from->has_new_buffer_transform)
+    {
+      to->buffer_transform = from->buffer_transform;
+      to->has_new_buffer_transform = TRUE;
+    }
+
   if (to->buffer && to->buffer_destroy_handler_id == 0)
     {
       to->buffer_destroy_handler_id =
@@ -682,6 +727,9 @@ meta_wayland_surface_apply_pending_state (MetaWaylandSurface      *surface,
   if (pending->scale > 0)
     surface->scale = pending->scale;
 
+  if (pending->has_new_buffer_transform)
+    surface->buffer_transform = pending->buffer_transform;
+
   if (meta_wayland_surface_get_actor (surface) &&
       (!cairo_region_is_empty (pending->surface_damage) ||
        !cairo_region_is_empty (pending->buffer_damage)))
@@ -926,12 +974,55 @@ wl_surface_commit (struct wl_client *client,
   meta_wayland_surface_commit (surface);
 }
 
+static MetaMonitorTransform
+transform_from_wl_output_transform (int32_t transform_value)
+{
+  enum wl_output_transform transform = transform_value;
+
+  switch (transform)
+    {
+    case WL_OUTPUT_TRANSFORM_NORMAL:
+      return META_MONITOR_TRANSFORM_NORMAL;
+    case WL_OUTPUT_TRANSFORM_90:
+      return META_MONITOR_TRANSFORM_90;
+    case WL_OUTPUT_TRANSFORM_180:
+      return META_MONITOR_TRANSFORM_180;
+    case WL_OUTPUT_TRANSFORM_270:
+      return META_MONITOR_TRANSFORM_270;
+    case WL_OUTPUT_TRANSFORM_FLIPPED:
+      return META_MONITOR_TRANSFORM_FLIPPED;
+    case WL_OUTPUT_TRANSFORM_FLIPPED_90:
+      return META_MONITOR_TRANSFORM_FLIPPED_90;
+    case WL_OUTPUT_TRANSFORM_FLIPPED_180:
+      return META_MONITOR_TRANSFORM_FLIPPED_180;
+    case WL_OUTPUT_TRANSFORM_FLIPPED_270:
+      return META_MONITOR_TRANSFORM_FLIPPED_270;
+    default:
+      return -1;
+    }
+}
+
 static void
-wl_surface_set_buffer_transform (struct wl_client *client,
+wl_surface_set_buffer_transform (struct wl_client   *client,
                                  struct wl_resource *resource,
-                                 int32_t transform)
+                                 int32_t             transform)
 {
-  g_warning ("TODO: support set_buffer_transform request");
+  MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
+  MetaMonitorTransform buffer_transform;
+
+  buffer_transform = transform_from_wl_output_transform (transform);
+
+  if (buffer_transform == -1)
+    {
+      wl_resource_post_error (resource,
+                              WL_SURFACE_ERROR_INVALID_TRANSFORM,
+                              "Trying to set invalid buffer_transform of %d\n",
+                              transform);
+      return;
+    }
+
+  surface->pending->buffer_transform = buffer_transform;
+  surface->pending->has_new_buffer_transform = TRUE;
 }
 
 static void
@@ -1750,33 +1841,25 @@ meta_wayland_surface_notify_geometry_changed (MetaWaylandSurface *surface)
 int
 meta_wayland_surface_get_width (MetaWaylandSurface *surface)
 {
-  MetaWaylandBuffer *buffer;
+  int width;
 
-  buffer = surface->buffer_ref.buffer;
-  if (buffer)
-    {
-      CoglTexture *texture = meta_wayland_buffer_get_texture (buffer);
-      return cogl_texture_get_width (texture) / surface->scale;
-    }
+  if (meta_monitor_transform_is_rotated (surface->buffer_transform))
+    width = get_buffer_height (surface);
   else
-    {
-      return 0;
-    }
+    width = get_buffer_width (surface);
+
+  return width / surface->scale;
 }
 
 int
 meta_wayland_surface_get_height (MetaWaylandSurface *surface)
 {
-  MetaWaylandBuffer *buffer;
+  int height;
 
-  buffer = surface->buffer_ref.buffer;
-  if (buffer)
-    {
-      CoglTexture *texture = meta_wayland_buffer_get_texture (buffer);
-      return cogl_texture_get_height (texture) / surface->scale;
-    }
+  if (meta_monitor_transform_is_rotated (surface->buffer_transform))
+    height = get_buffer_width (surface);
   else
-    {
-      return 0;
-    }
+    height = get_buffer_height (surface);
+
+  return height / surface->scale;
 }
diff --git a/src/wayland/meta-wayland-surface.h b/src/wayland/meta-wayland-surface.h
index dd8009b8b..abba1c765 100644
--- a/src/wayland/meta-wayland-surface.h
+++ b/src/wayland/meta-wayland-surface.h
@@ -27,6 +27,7 @@
 
 #include "backends/meta-monitor-manager-private.h"
 #include "clutter/clutter.h"
+#include "compositor/meta-shaped-texture-private.h"
 #include "compositor/meta-surface-actor.h"
 #include "meta/meta-cursor-tracker.h"
 #include "wayland/meta-wayland-pointer-constraints.h"
@@ -109,6 +110,9 @@ struct _MetaWaylandPendingState
   gboolean has_new_max_size;
   int new_max_width;
   int new_max_height;
+
+  gboolean has_new_buffer_transform;
+  MetaMonitorTransform buffer_transform;
 };
 
 struct _MetaWaylandDragDestFuncs
@@ -142,6 +146,7 @@ struct _MetaWaylandSurface
   int32_t offset_x, offset_y;
   GList *subsurfaces;
   GHashTable *outputs_to_destroy_notify_id;
+  MetaMonitorTransform buffer_transform;
 
   /* Buffer reference state. */
   struct {


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