[mutter] cursor-renderer/native: Implement scaled/transformed hardware cursors



commit 987ce5bec0ff50f812dbc7c60a471d7ca3eca656
Author: Robert Mader <robert mader posteo de>
Date:   Mon May 13 10:21:40 2019 +0200

    cursor-renderer/native: Implement scaled/transformed hardware cursors
    
    If the cursor sprite does not match the scale factor or transformation
    of the monintor, we currently fall back to a software cursor, causing
    redraws of the shell. This commit implements scaling and transforming
    of the cursor sprite, so we can use it with hardware planes, too.
    
    This commit does the following steps:
    
    1. Make sure we reupload the cursor image if the cursor is over
    a logical monitor not matching the scale or transform from the previous
    update.
    2. Before upload to the hardware plane, scale and transform the cursor
    image if possible and necessary.
    3. Make sure we always use the hardware cursor if possible (only fall
    back to software/OGL cursor if it is visible on multiple logical monitors
    with differet scales/transforms).
    4. Transform or scale the cursor coordinates if necessary.
    
    https://gitlab.gnome.org/GNOME/mutter/merge_requests/526

 src/backends/native/meta-cursor-renderer-native.c | 453 ++++++++++++++++++----
 1 file changed, 379 insertions(+), 74 deletions(-)
---
diff --git a/src/backends/native/meta-cursor-renderer-native.c 
b/src/backends/native/meta-cursor-renderer-native.c
index 4195b60a0..6526d3d76 100644
--- a/src/backends/native/meta-cursor-renderer-native.c
+++ b/src/backends/native/meta-cursor-renderer-native.c
@@ -117,6 +117,12 @@ typedef struct _MetaCursorNativeGpuState
 typedef struct _MetaCursorNativePrivate
 {
   GHashTable *gpu_states;
+
+  struct {
+    gboolean can_preprocess;
+    float current_relative_scale;
+    MetaMonitorTransform current_relative_transform;
+  } preprocess_state;
 } MetaCursorNativePrivate;
 
 static GQuark quark_cursor_renderer_native_gpu_data = 0;
@@ -136,6 +142,9 @@ static MetaCursorNativeGpuState *
 ensure_cursor_gpu_state (MetaCursorNativePrivate *cursor_priv,
                          MetaGpuKms              *gpu_kms);
 
+static void
+invalidate_cursor_gpu_state (MetaCursorSprite *cursor_sprite);
+
 static MetaCursorNativePrivate *
 ensure_cursor_priv (MetaCursorSprite *cursor_sprite);
 
@@ -311,6 +320,21 @@ unset_crtc_cursor (MetaCursorRendererNative *native,
   crtc->cursor_renderer_private = NULL;
 }
 
+static float
+calculate_cursor_crtc_sprite_scale (MetaCursorSprite   *cursor_sprite,
+                                    MetaLogicalMonitor *logical_monitor)
+{
+  if (meta_is_stage_views_scaled ())
+    {
+      return (meta_logical_monitor_get_scale (logical_monitor) *
+              meta_cursor_sprite_get_texture_scale (cursor_sprite));
+    }
+  else
+    {
+      return 1.0;
+    }
+}
+
 typedef struct
 {
   MetaCursorRendererNative *in_cursor_renderer_native;
@@ -382,18 +406,45 @@ update_monitor_crtc_cursor (MetaMonitor         *monitor,
                                   &data->in_local_cursor_rect,
                                   NULL))
     {
+      MetaMonitorTransform inverted_transform;
+      MetaRectangle cursor_rect;
+      CoglTexture *texture;
       float crtc_cursor_x, crtc_cursor_y;
+      float cursor_crtc_scale;
+      int tex_width, tex_height;
 
       crtc_cursor_x = (data->in_local_cursor_rect.origin.x -
                        scaled_crtc_rect.origin.x) * scale;
       crtc_cursor_y = (data->in_local_cursor_rect.origin.y -
                        scaled_crtc_rect.origin.y) * scale;
 
+      texture = meta_cursor_sprite_get_cogl_texture (data->in_cursor_sprite);
+      tex_width = cogl_texture_get_width (texture);
+      tex_height = cogl_texture_get_height (texture);
+
+      cursor_crtc_scale =
+        calculate_cursor_crtc_sprite_scale (data->in_cursor_sprite,
+                                            data->in_logical_monitor);
+
+      cursor_rect = (MetaRectangle) {
+        .x = floorf (crtc_cursor_x),
+        .y = floorf (crtc_cursor_y),
+        .width = roundf (tex_width * cursor_crtc_scale),
+        .height = roundf (tex_height * cursor_crtc_scale)
+      };
+
+      inverted_transform = meta_monitor_transform_invert (transform);
+      meta_rectangle_transform (&cursor_rect,
+                                inverted_transform,
+                                monitor_crtc_mode->crtc_mode->width,
+                                monitor_crtc_mode->crtc_mode->height,
+                                &cursor_rect);
+
       set_crtc_cursor (data->in_cursor_renderer_native,
                        data->in_kms_update,
                        crtc,
-                       (int) floorf (crtc_cursor_x),
-                       (int) floorf (crtc_cursor_y),
+                       cursor_rect.x,
+                       cursor_rect.y,
                        data->in_cursor_sprite);
 
       data->out_painted = data->out_painted || TRUE;
@@ -543,9 +594,61 @@ has_valid_cursor_sprite_gbm_bo (MetaCursorSprite *cursor_sprite,
   return FALSE;
 }
 
+static void
+set_can_preprocess (MetaCursorSprite     *cursor_sprite,
+                    float                 scale,
+                    MetaMonitorTransform  transform)
+{
+  MetaCursorNativePrivate *cursor_priv = get_cursor_priv (cursor_sprite);
+
+  cursor_priv->preprocess_state.current_relative_scale = scale;
+  cursor_priv->preprocess_state.current_relative_transform = transform;
+  cursor_priv->preprocess_state.can_preprocess = TRUE;
+
+  invalidate_cursor_gpu_state (cursor_sprite);
+}
+
+static void
+unset_can_preprocess (MetaCursorSprite *cursor_sprite)
+{
+  MetaCursorNativePrivate *cursor_priv = get_cursor_priv (cursor_sprite);
+
+  memset (&cursor_priv->preprocess_state,
+          0,
+          sizeof (cursor_priv->preprocess_state));
+  cursor_priv->preprocess_state.can_preprocess = FALSE;
+
+  invalidate_cursor_gpu_state (cursor_sprite);
+}
+
 static gboolean
-cursor_over_transformed_logical_monitor (MetaCursorRenderer *renderer,
-                                         MetaCursorSprite   *cursor_sprite)
+get_can_preprocess (MetaCursorSprite *cursor_sprite)
+{
+  MetaCursorNativePrivate *cursor_priv = get_cursor_priv (cursor_sprite);
+
+  return cursor_priv->preprocess_state.can_preprocess;
+}
+
+static float
+get_current_relative_scale (MetaCursorSprite *cursor_sprite)
+{
+  MetaCursorNativePrivate *cursor_priv = get_cursor_priv (cursor_sprite);
+
+  return cursor_priv->preprocess_state.current_relative_scale;
+}
+
+static MetaMonitorTransform
+get_current_relative_transform (MetaCursorSprite *cursor_sprite)
+{
+  MetaCursorNativePrivate *cursor_priv = get_cursor_priv (cursor_sprite);
+
+  return cursor_priv->preprocess_state.current_relative_transform;
+}
+
+static gboolean
+get_common_crtc_sprite_scale_for_logical_monitors (MetaCursorRenderer *renderer,
+                                                   MetaCursorSprite   *cursor_sprite,
+                                                   float              *out_scale)
 {
   MetaCursorRendererNative *cursor_renderer_native =
     META_CURSOR_RENDERER_NATIVE (renderer);
@@ -554,58 +657,50 @@ cursor_over_transformed_logical_monitor (MetaCursorRenderer *renderer,
   MetaBackend *backend = priv->backend;
   MetaMonitorManager *monitor_manager =
     meta_backend_get_monitor_manager (backend);
+  graphene_rect_t cursor_rect;
+  float scale = 1.0;
+  gboolean has_visible_crtc_sprite = FALSE;
   GList *logical_monitors;
   GList *l;
-  graphene_rect_t cursor_rect;
 
   cursor_rect = meta_cursor_renderer_calculate_rect (renderer, cursor_sprite);
 
   logical_monitors =
     meta_monitor_manager_get_logical_monitors (monitor_manager);
+
   for (l = logical_monitors; l; l = l->next)
     {
       MetaLogicalMonitor *logical_monitor = l->data;
-      MetaRectangle logical_monitor_layout;
-      graphene_rect_t logical_monitor_rect;
-      MetaMonitorTransform transform;
-      GList *monitors, *l_mon;
-
-      logical_monitor_layout =
-        meta_logical_monitor_get_layout (logical_monitor);
-      logical_monitor_rect =
-        meta_rectangle_to_graphene_rect (&logical_monitor_layout);
+      graphene_rect_t logical_monitor_rect =
+        meta_rectangle_to_graphene_rect (&logical_monitor->rect);
+      float tmp_scale;
 
-      if (!graphene_rect_intersection (&cursor_rect, &logical_monitor_rect,
+      if (!graphene_rect_intersection (&cursor_rect,
+                                       &logical_monitor_rect,
                                        NULL))
         continue;
 
-      monitors = meta_logical_monitor_get_monitors (logical_monitor);
-      for (l_mon = monitors; l_mon; l_mon = l_mon->next)
-        {
-          MetaMonitor *monitor = l_mon->data;
+      tmp_scale =
+        calculate_cursor_crtc_sprite_scale (cursor_sprite, logical_monitor);
 
-          transform = meta_logical_monitor_get_transform (logical_monitor);
-          /* Get transform corrected for LCD panel-orientation. */
-          transform = meta_monitor_logical_to_crtc_transform (monitor, transform);
-          if (transform != META_MONITOR_TRANSFORM_NORMAL)
-            return TRUE;
-        }
+      if (has_visible_crtc_sprite && scale != tmp_scale)
+        return FALSE;
+
+      has_visible_crtc_sprite = TRUE;
+      scale = tmp_scale;
     }
 
-  return FALSE;
-}
+  if (!has_visible_crtc_sprite)
+    return FALSE;
 
-static float
-calculate_cursor_crtc_sprite_scale (MetaCursorSprite   *cursor_sprite,
-                                    MetaLogicalMonitor *logical_monitor)
-{
-  return (meta_logical_monitor_get_scale (logical_monitor) *
-          meta_cursor_sprite_get_texture_scale (cursor_sprite));
+  *out_scale = scale;
+  return TRUE;
 }
 
 static gboolean
-can_draw_cursor_unscaled (MetaCursorRenderer *renderer,
-                          MetaCursorSprite   *cursor_sprite)
+get_common_crtc_sprite_transform_for_logical_monitors (MetaCursorRenderer   *renderer,
+                                                       MetaCursorSprite     *cursor_sprite,
+                                                       MetaMonitorTransform *out_transform)
 {
   MetaCursorRendererNative *cursor_renderer_native =
     META_CURSOR_RENDERER_NATIVE (renderer);
@@ -615,40 +710,44 @@ can_draw_cursor_unscaled (MetaCursorRenderer *renderer,
   MetaMonitorManager *monitor_manager =
     meta_backend_get_monitor_manager (backend);
   graphene_rect_t cursor_rect;
+  MetaMonitorTransform transform = META_MONITOR_TRANSFORM_NORMAL;
+  gboolean has_visible_crtc_sprite = FALSE;
   GList *logical_monitors;
   GList *l;
-  gboolean has_visible_crtc_sprite = FALSE;
 
-  if (!meta_is_stage_views_scaled ())
-   return meta_cursor_sprite_get_texture_scale (cursor_sprite) == 1.0;
+  cursor_rect = meta_cursor_renderer_calculate_rect (renderer, cursor_sprite);
 
   logical_monitors =
     meta_monitor_manager_get_logical_monitors (monitor_manager);
 
-  if (!logical_monitors)
-    return FALSE;
-
-  cursor_rect = meta_cursor_renderer_calculate_rect (renderer, cursor_sprite);
-
   for (l = logical_monitors; l; l = l->next)
     {
       MetaLogicalMonitor *logical_monitor = l->data;
       graphene_rect_t logical_monitor_rect =
         meta_rectangle_to_graphene_rect (&logical_monitor->rect);
+      MetaMonitorTransform tmp_transform;
 
       if (!graphene_rect_intersection (&cursor_rect,
                                        &logical_monitor_rect,
                                        NULL))
         continue;
 
-      if (calculate_cursor_crtc_sprite_scale (cursor_sprite,
-                                              logical_monitor) != 1.0)
+      tmp_transform = meta_monitor_transform_relative_transform (
+        meta_cursor_sprite_get_texture_transform (cursor_sprite),
+        meta_logical_monitor_get_transform (logical_monitor));
+
+      if (has_visible_crtc_sprite && transform != tmp_transform)
         return FALSE;
 
       has_visible_crtc_sprite = TRUE;
+      transform = tmp_transform;
     }
 
-  return has_visible_crtc_sprite;
+  if (!has_visible_crtc_sprite)
+    return FALSE;
+
+  *out_transform = transform;
+  return TRUE;
 }
 
 static gboolean
@@ -656,8 +755,10 @@ should_have_hw_cursor (MetaCursorRenderer *renderer,
                        MetaCursorSprite   *cursor_sprite,
                        GList              *gpus)
 {
-  GList *l;
   CoglTexture *texture;
+  MetaMonitorTransform transform;
+  float scale;
+  GList *l;
 
   if (!cursor_sprite)
     return FALSE;
@@ -683,16 +784,26 @@ should_have_hw_cursor (MetaCursorRenderer *renderer,
         return FALSE;
     }
 
-  if (cursor_over_transformed_logical_monitor (renderer, cursor_sprite))
-    return FALSE;
-
   texture = meta_cursor_sprite_get_cogl_texture (cursor_sprite);
   if (!texture)
     return FALSE;
 
-  if (!can_draw_cursor_unscaled (renderer, cursor_sprite))
+  if (!get_common_crtc_sprite_scale_for_logical_monitors (renderer,
+                                                          cursor_sprite,
+                                                          &scale))
+    return FALSE;
+
+  if (!get_common_crtc_sprite_transform_for_logical_monitors (renderer,
+                                                              cursor_sprite,
+                                                              &transform))
     return FALSE;
 
+  if (G_APPROX_VALUE (scale, 1.f, FLT_EPSILON) &&
+      transform == META_MONITOR_TRANSFORM_NORMAL)
+    return TRUE;
+  else
+    return get_can_preprocess (cursor_sprite);
+
   return TRUE;
 }
 
@@ -875,7 +986,7 @@ ensure_cursor_gpu_state (MetaCursorNativePrivate *cursor_priv,
 }
 
 static void
-on_cursor_sprite_texture_changed (MetaCursorSprite *cursor_sprite)
+invalidate_cursor_gpu_state (MetaCursorSprite *cursor_sprite)
 {
   MetaCursorNativePrivate *cursor_priv = get_cursor_priv (cursor_sprite);
   GHashTableIter iter;
@@ -892,6 +1003,12 @@ on_cursor_sprite_texture_changed (MetaCursorSprite *cursor_sprite)
     }
 }
 
+static void
+on_cursor_sprite_texture_changed (MetaCursorSprite *cursor_sprite)
+{
+  invalidate_cursor_gpu_state (cursor_sprite);
+}
+
 static void
 cursor_priv_free (MetaCursorNativePrivate *cursor_priv)
 {
@@ -928,6 +1045,8 @@ ensure_cursor_priv (MetaCursorSprite *cursor_sprite)
   g_signal_connect (cursor_sprite, "texture-changed",
                     G_CALLBACK (on_cursor_sprite_texture_changed), NULL);
 
+  unset_can_preprocess (cursor_sprite);
+
   return cursor_priv;
 }
 
@@ -1023,6 +1142,147 @@ is_cursor_hw_state_valid (MetaCursorSprite *cursor_sprite,
   return FALSE;
 }
 
+static gboolean
+is_cursor_scale_and_transform_valid (MetaCursorRenderer *renderer,
+                                     MetaCursorSprite   *cursor_sprite)
+{
+  MetaMonitorTransform transform;
+  float scale;
+
+  if (!get_common_crtc_sprite_scale_for_logical_monitors (renderer,
+                                                          cursor_sprite,
+                                                          &scale))
+    return FALSE;
+
+  if (!get_common_crtc_sprite_transform_for_logical_monitors (renderer,
+                                                              cursor_sprite,
+                                                              &transform))
+    return FALSE;
+
+  return (scale == get_current_relative_scale (cursor_sprite) &&
+          transform == get_current_relative_transform (cursor_sprite));
+}
+
+static cairo_surface_t *
+scale_and_transform_cursor_sprite_cpu (uint8_t              *pixels,
+                                       int                   width,
+                                       int                   height,
+                                       int                   rowstride,
+                                       float                 scale,
+                                       MetaMonitorTransform  transform)
+{
+  cairo_t *cr;
+  cairo_surface_t *source_surface;
+  cairo_surface_t *target_surface;
+  int image_width;
+  int image_height;
+
+  image_width = ceilf (width * scale);
+  image_height = ceilf (height * scale);
+
+  target_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
+                                               image_width,
+                                               image_height);
+
+  cr = cairo_create (target_surface);
+  if (transform != META_MONITOR_TRANSFORM_NORMAL)
+    {
+      cairo_translate (cr, 0.5 * image_width, 0.5 * image_height);
+      switch (transform)
+        {
+        case META_MONITOR_TRANSFORM_90:
+          cairo_rotate (cr, M_PI * 1.5);
+          break;
+        case META_MONITOR_TRANSFORM_180:
+          cairo_rotate (cr, M_PI);
+          break;
+        case META_MONITOR_TRANSFORM_270:
+          cairo_rotate (cr, M_PI * 0.5);
+          break;
+        case META_MONITOR_TRANSFORM_FLIPPED:
+          cairo_scale (cr, 1, -1);
+          break;
+        case META_MONITOR_TRANSFORM_FLIPPED_90:
+          cairo_rotate (cr, M_PI * 1.5);
+          cairo_scale (cr, -1, 1);
+          break;
+        case META_MONITOR_TRANSFORM_FLIPPED_180:
+          cairo_rotate (cr, M_PI);
+          cairo_scale (cr, 1, -1);
+          break;
+        case META_MONITOR_TRANSFORM_FLIPPED_270:
+          cairo_rotate (cr, M_PI * 0.5);
+          cairo_scale (cr, -1, 1);
+          break;
+        case META_MONITOR_TRANSFORM_NORMAL:
+          g_assert_not_reached ();
+        }
+      cairo_translate (cr, -0.5 * image_width, -0.5 * image_height);
+    }
+  cairo_scale (cr, scale, scale);
+
+  source_surface = cairo_image_surface_create_for_data (pixels,
+                                                        CAIRO_FORMAT_ARGB32,
+                                                        width,
+                                                        height,
+                                                        rowstride);
+
+  cairo_set_source_surface (cr, source_surface, 0, 0);
+  cairo_paint (cr);
+  cairo_destroy (cr);
+  cairo_surface_destroy (source_surface);
+
+  return target_surface;
+}
+
+static void
+load_scaled_and_transformed_cursor_sprite (MetaCursorRendererNative *native,
+                                           MetaGpuKms               *gpu_kms,
+                                           MetaCursorSprite         *cursor_sprite,
+                                           float                     relative_scale,
+                                           MetaMonitorTransform      relative_transform,
+                                           uint8_t                  *data,
+                                           int                       width,
+                                           int                       height,
+                                           int                       rowstride,
+                                           uint32_t                  gbm_format)
+{
+  if (!G_APPROX_VALUE (relative_scale, 1.f, FLT_EPSILON) ||
+      relative_transform != META_MONITOR_TRANSFORM_NORMAL)
+    {
+      cairo_surface_t *surface;
+
+      surface = scale_and_transform_cursor_sprite_cpu (data,
+                                                       width,
+                                                       height,
+                                                       rowstride,
+                                                       relative_scale,
+                                                       relative_transform);
+
+      load_cursor_sprite_gbm_buffer_for_gpu (native,
+                                             gpu_kms,
+                                             cursor_sprite,
+                                             cairo_image_surface_get_data (surface),
+                                             cairo_image_surface_get_width (surface),
+                                             cairo_image_surface_get_width (surface),
+                                             cairo_image_surface_get_stride (surface),
+                                             gbm_format);
+
+      cairo_surface_destroy (surface);
+    }
+  else
+    {
+      load_cursor_sprite_gbm_buffer_for_gpu (native,
+                                             gpu_kms,
+                                             cursor_sprite,
+                                             data,
+                                             width,
+                                             height,
+                                             rowstride,
+                                             gbm_format);
+    }
+}
+
 #ifdef HAVE_WAYLAND
 static void
 realize_cursor_sprite_from_wl_buffer_for_gpu (MetaCursorRenderer      *renderer,
@@ -1032,7 +1292,6 @@ realize_cursor_sprite_from_wl_buffer_for_gpu (MetaCursorRenderer      *renderer,
   MetaCursorRendererNative *native = META_CURSOR_RENDERER_NATIVE (renderer);
   MetaCursorSprite *cursor_sprite = META_CURSOR_SPRITE (sprite_wayland);
   MetaCursorRendererNativeGpuData *cursor_renderer_gpu_data;
-  uint32_t gbm_format;
   uint64_t cursor_width, cursor_height;
   CoglTexture *texture;
   uint width, height;
@@ -1045,13 +1304,10 @@ realize_cursor_sprite_from_wl_buffer_for_gpu (MetaCursorRenderer      *renderer,
   if (!cursor_renderer_gpu_data || cursor_renderer_gpu_data->hw_cursor_broken)
     return;
 
-  if (is_cursor_hw_state_valid (cursor_sprite, gpu_kms))
+  if (is_cursor_hw_state_valid (cursor_sprite, gpu_kms) &&
+      is_cursor_scale_and_transform_valid (renderer, cursor_sprite))
     return;
 
-  texture = meta_cursor_sprite_get_cogl_texture (cursor_sprite);
-  width = cogl_texture_get_width (texture);
-  height = cogl_texture_get_height (texture);
-
   buffer = meta_cursor_sprite_wayland_get_buffer (sprite_wayland);
   if (!buffer)
     return;
@@ -1060,13 +1316,22 @@ realize_cursor_sprite_from_wl_buffer_for_gpu (MetaCursorRenderer      *renderer,
   if (!buffer_resource)
     return;
 
+  ensure_cursor_priv (cursor_sprite);
+
   shm_buffer = wl_shm_buffer_get (buffer_resource);
   if (shm_buffer)
     {
       int rowstride = wl_shm_buffer_get_stride (shm_buffer);
       uint8_t *buffer_data;
+      float relative_scale;
+      MetaMonitorTransform relative_transform;
+      uint32_t gbm_format;
 
       wl_shm_buffer_begin_access (shm_buffer);
+      buffer_data = wl_shm_buffer_get_data (shm_buffer);
+
+      width = wl_shm_buffer_get_width (shm_buffer);
+      height = wl_shm_buffer_get_width (shm_buffer);
 
       switch (wl_shm_buffer_get_format (shm_buffer))
         {
@@ -1090,13 +1355,28 @@ realize_cursor_sprite_from_wl_buffer_for_gpu (MetaCursorRenderer      *renderer,
           gbm_format = GBM_FORMAT_ARGB8888;
         }
 
-      buffer_data = wl_shm_buffer_get_data (shm_buffer);
-      load_cursor_sprite_gbm_buffer_for_gpu (native,
-                                             gpu_kms,
-                                             cursor_sprite,
-                                             buffer_data,
-                                             width, height, rowstride,
-                                             gbm_format);
+      get_common_crtc_sprite_scale_for_logical_monitors (renderer,
+                                                         cursor_sprite,
+                                                         &relative_scale);
+
+      get_common_crtc_sprite_transform_for_logical_monitors (renderer,
+                                                             cursor_sprite,
+                                                             &relative_transform);
+
+      set_can_preprocess (cursor_sprite,
+                          relative_scale,
+                          relative_transform);
+
+      load_scaled_and_transformed_cursor_sprite (native,
+                                                 gpu_kms,
+                                                 cursor_sprite,
+                                                 relative_scale,
+                                                 relative_transform,
+                                                 buffer_data,
+                                                 width,
+                                                 height,
+                                                 rowstride,
+                                                 gbm_format);
 
       wl_shm_buffer_end_access (shm_buffer);
     }
@@ -1114,6 +1394,10 @@ realize_cursor_sprite_from_wl_buffer_for_gpu (MetaCursorRenderer      *renderer,
       cursor_width = (uint64_t) cursor_renderer_gpu_data->cursor_width;
       cursor_height = (uint64_t) cursor_renderer_gpu_data->cursor_height;
 
+      texture = meta_cursor_sprite_get_cogl_texture (cursor_sprite);
+      width = cogl_texture_get_width (texture);
+      height = cogl_texture_get_height (texture);
+
       if (width != cursor_width || height != cursor_height)
         {
           meta_warning ("Invalid cursor size (must be 64x64), falling back to software (GL) cursors\n");
@@ -1131,6 +1415,8 @@ realize_cursor_sprite_from_wl_buffer_for_gpu (MetaCursorRenderer      *renderer,
           return;
         }
 
+      unset_can_preprocess (cursor_sprite);
+
       set_pending_cursor_sprite_gbm_bo (cursor_sprite, gpu_kms, bo);
     }
 }
@@ -1145,25 +1431,44 @@ realize_cursor_sprite_from_xcursor_for_gpu (MetaCursorRenderer      *renderer,
   MetaCursorRendererNativeGpuData *cursor_renderer_gpu_data;
   MetaCursorSprite *cursor_sprite = META_CURSOR_SPRITE (sprite_xcursor);
   XcursorImage *xc_image;
+  float relative_scale;
+  MetaMonitorTransform relative_transform;
+
+  ensure_cursor_priv (cursor_sprite);
 
   cursor_renderer_gpu_data =
     meta_cursor_renderer_native_gpu_data_from_gpu (gpu_kms);
   if (!cursor_renderer_gpu_data || cursor_renderer_gpu_data->hw_cursor_broken)
     return;
 
-  if (is_cursor_hw_state_valid (cursor_sprite, gpu_kms))
+  if (is_cursor_hw_state_valid (cursor_sprite, gpu_kms) &&
+      is_cursor_scale_and_transform_valid (renderer, cursor_sprite))
     return;
 
   xc_image = meta_cursor_sprite_xcursor_get_current_image (sprite_xcursor);
 
-  load_cursor_sprite_gbm_buffer_for_gpu (native,
-                                         gpu_kms,
-                                         cursor_sprite,
-                                         (uint8_t *) xc_image->pixels,
-                                         xc_image->width,
-                                         xc_image->height,
-                                         xc_image->width * 4,
-                                         GBM_FORMAT_ARGB8888);
+  get_common_crtc_sprite_scale_for_logical_monitors (renderer,
+                                                     cursor_sprite,
+                                                     &relative_scale);
+
+  get_common_crtc_sprite_transform_for_logical_monitors (renderer,
+                                                         cursor_sprite,
+                                                         &relative_transform);
+
+  set_can_preprocess (cursor_sprite,
+                      relative_scale,
+                      relative_transform);
+
+  load_scaled_and_transformed_cursor_sprite (native,
+                                             gpu_kms,
+                                             cursor_sprite,
+                                             relative_scale,
+                                             relative_transform,
+                                             (uint8_t *) xc_image->pixels,
+                                             xc_image->width,
+                                             xc_image->height,
+                                             xc_image->width * 4,
+                                             GBM_FORMAT_ARGB8888);
 }
 
 static void


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