[mutter] cursor-renderer/native: Update HW state during frames



commit c98575344295b715a0301c7319195b2724dc2bde
Author: Jonas Ã…dahl <jadahl gmail com>
Date:   Sat Oct 10 01:02:28 2020 +0200

    cursor-renderer/native: Update HW state during frames
    
    Before each frame is maybe redrawn, push any new cursor KMS state to the
    pending update. It'll then either be posted during the next page flip,
    or when the same frame finishes, in case nothing was redrawn.
    
    Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1488>

 clutter/clutter/clutter-stage-view.c              |   2 +
 clutter/clutter/clutter-stage-window.c            |  11 +
 clutter/clutter/clutter-stage-window.h            |   7 +
 clutter/clutter/cogl/clutter-stage-cogl.c         |  15 +
 clutter/clutter/cogl/clutter-stage-cogl.h         |   4 +
 src/backends/meta-monitor.c                       |  22 ++
 src/backends/meta-monitor.h                       |   4 +
 src/backends/native/meta-cursor-renderer-native.c | 451 ++++++++++------------
 src/backends/native/meta-cursor-renderer-native.h |   3 +
 src/backends/native/meta-renderer-native.c        |  75 +++-
 src/backends/native/meta-renderer-native.h        |   6 +-
 src/backends/native/meta-stage-native.c           |  24 +-
 12 files changed, 363 insertions(+), 261 deletions(-)
---
diff --git a/clutter/clutter/clutter-stage-view.c b/clutter/clutter/clutter-stage-view.c
index 66d052ebe7..436ce40b29 100644
--- a/clutter/clutter/clutter-stage-view.c
+++ b/clutter/clutter/clutter-stage-view.c
@@ -1099,6 +1099,8 @@ handle_frame_clock_frame (ClutterFrameClock *frame_clock,
 
   frame = CLUTTER_FRAME_INIT;
 
+  _clutter_stage_window_prepare_frame (stage_window, view, &frame);
+
   if (clutter_stage_view_has_redraw_clip (view))
     {
       clutter_stage_emit_before_paint (stage, view);
diff --git a/clutter/clutter/clutter-stage-window.c b/clutter/clutter/clutter-stage-window.c
index 5f7c489675..9052a8c4bf 100644
--- a/clutter/clutter/clutter-stage-window.c
+++ b/clutter/clutter/clutter-stage-window.c
@@ -135,6 +135,17 @@ _clutter_stage_window_get_views (ClutterStageWindow *window)
   return iface->get_views (window);
 }
 
+void
+_clutter_stage_window_prepare_frame (ClutterStageWindow *window,
+                                     ClutterStageView   *view,
+                                     ClutterFrame       *frame)
+{
+  ClutterStageWindowInterface *iface = CLUTTER_STAGE_WINDOW_GET_IFACE (window);
+
+  if (iface->prepare_frame)
+    iface->prepare_frame (window, view, frame);
+}
+
 void
 _clutter_stage_window_finish_frame (ClutterStageWindow *window,
                                     ClutterStageView   *view,
diff --git a/clutter/clutter/clutter-stage-window.h b/clutter/clutter/clutter-stage-window.h
index b1ebd2badf..5f0ae7ab16 100644
--- a/clutter/clutter/clutter-stage-window.h
+++ b/clutter/clutter/clutter-stage-window.h
@@ -52,6 +52,9 @@ struct _ClutterStageWindowInterface
 
   GList            *(* get_views)               (ClutterStageWindow *stage_window);
   int64_t           (* get_frame_counter)       (ClutterStageWindow *stage_window);
+  void              (* prepare_frame)           (ClutterStageWindow *stage_window,
+                                                 ClutterStageView   *view,
+                                                 ClutterFrame       *frame);
   void              (* finish_frame)            (ClutterStageWindow *stage_window,
                                                  ClutterStageView   *view,
                                                  ClutterFrame       *frame);
@@ -89,6 +92,10 @@ gboolean          _clutter_stage_window_can_clip_redraws        (ClutterStageWin
 
 GList *           _clutter_stage_window_get_views               (ClutterStageWindow *window);
 
+void              _clutter_stage_window_prepare_frame           (ClutterStageWindow *window,
+                                                                 ClutterStageView   *view,
+                                                                 ClutterFrame       *frame);
+
 void              _clutter_stage_window_finish_frame            (ClutterStageWindow *window,
                                                                  ClutterStageView   *view,
                                                                  ClutterFrame       *frame);
diff --git a/clutter/clutter/cogl/clutter-stage-cogl.c b/clutter/clutter/cogl/clutter-stage-cogl.c
index 90f428ec81..2e14ec9ebc 100644
--- a/clutter/clutter/cogl/clutter-stage-cogl.c
+++ b/clutter/clutter/cogl/clutter-stage-cogl.c
@@ -731,6 +731,21 @@ clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window,
   clutter_stage_cogl_redraw_view_primary (stage_cogl, view, frame);
 }
 
+void
+clutter_stage_cogl_add_onscreen_frame_info (ClutterStageCogl *stage_cogl,
+                                            ClutterStageView *view)
+{
+  ClutterStageCoglPrivate *priv =
+    _clutter_stage_cogl_get_instance_private (stage_cogl);
+  CoglFramebuffer *framebuffer = clutter_stage_view_get_onscreen (view);
+  CoglFrameInfo *frame_info;
+
+  frame_info = cogl_frame_info_new (priv->global_frame_counter);
+  priv->global_frame_counter++;
+
+  cogl_onscreen_add_frame_info (COGL_ONSCREEN (framebuffer), frame_info);
+}
+
 static void
 clutter_stage_window_iface_init (ClutterStageWindowInterface *iface)
 {
diff --git a/clutter/clutter/cogl/clutter-stage-cogl.h b/clutter/clutter/cogl/clutter-stage-cogl.h
index a67ba96152..11aeaefe12 100644
--- a/clutter/clutter/cogl/clutter-stage-cogl.h
+++ b/clutter/clutter/cogl/clutter-stage-cogl.h
@@ -56,6 +56,10 @@ void _clutter_stage_cogl_presented (ClutterStageCogl *stage_cogl,
                                     CoglFrameEvent    frame_event,
                                     ClutterFrameInfo *frame_info);
 
+CLUTTER_EXPORT
+void clutter_stage_cogl_add_onscreen_frame_info (ClutterStageCogl *stage_cogl,
+                                                 ClutterStageView *view);
+
 G_END_DECLS
 
 #endif /* __CLUTTER_STAGE_COGL_H__ */
diff --git a/src/backends/meta-monitor.c b/src/backends/meta-monitor.c
index 07c574de2b..0be7994ad5 100644
--- a/src/backends/meta-monitor.c
+++ b/src/backends/meta-monitor.c
@@ -1948,6 +1948,28 @@ meta_monitor_mode_foreach_output (MetaMonitor          *monitor,
   return TRUE;
 }
 
+MetaMonitorCrtcMode *
+meta_monitor_get_crtc_mode_for_output (MetaMonitor     *monitor,
+                                       MetaMonitorMode *mode,
+                                       MetaOutput      *output)
+{
+  MetaMonitorPrivate *monitor_priv =
+    meta_monitor_get_instance_private (monitor);
+  GList *l;
+  int i;
+
+  for (l = monitor_priv->outputs, i = 0; l; l = l->next, i++)
+    {
+      MetaMonitorCrtcMode *monitor_crtc_mode = &mode->crtc_modes[i];
+
+      if (monitor_crtc_mode->output == output)
+        return monitor_crtc_mode;
+    }
+
+  g_warn_if_reached ();
+  return NULL;
+}
+
 const char *
 meta_monitor_get_display_name (MetaMonitor *monitor)
 {
diff --git a/src/backends/meta-monitor.h b/src/backends/meta-monitor.h
index eb6b99fea1..96f280a89e 100644
--- a/src/backends/meta-monitor.h
+++ b/src/backends/meta-monitor.h
@@ -264,6 +264,10 @@ gboolean meta_monitor_mode_foreach_output (MetaMonitor          *monitor,
                                            gpointer              user_data,
                                            GError              **error);
 
+MetaMonitorCrtcMode * meta_monitor_get_crtc_mode_for_output (MetaMonitor     *monitor,
+                                                             MetaMonitorMode *mode,
+                                                             MetaOutput      *output);
+
 META_EXPORT_TEST
 gboolean meta_monitor_mode_should_be_advertised (MetaMonitorMode *monitor_mode);
 
diff --git a/src/backends/native/meta-cursor-renderer-native.c 
b/src/backends/native/meta-cursor-renderer-native.c
index ff175e8e2e..3899bd205c 100644
--- a/src/backends/native/meta-cursor-renderer-native.c
+++ b/src/backends/native/meta-cursor-renderer-native.c
@@ -80,6 +80,8 @@ static GQuark quark_cursor_sprite = 0;
 typedef struct _CrtcCursorData
 {
   MetaDrmBuffer *buffer;
+  gboolean needs_sync_position;
+  gboolean hw_state_invalidated;
 } CrtcCursorData;
 
 struct _MetaCursorRendererNative
@@ -91,7 +93,6 @@ struct _MetaCursorRendererNativePrivate
 {
   MetaBackend *backend;
 
-  gboolean hw_state_invalidated;
   gboolean has_hw_cursor;
 
   MetaCursorSprite *last_cursor;
@@ -137,6 +138,10 @@ static GQuark quark_cursor_renderer_native_gpu_data = 0;
 
 G_DEFINE_TYPE_WITH_PRIVATE (MetaCursorRendererNative, meta_cursor_renderer_native, 
META_TYPE_CURSOR_RENDERER);
 
+static void
+on_kms_update_result (const MetaKmsFeedback *kms_feedback,
+                      gpointer               user_data);
+
 static void
 realize_cursor_sprite (MetaCursorRenderer *renderer,
                        MetaCursorSprite   *cursor_sprite,
@@ -266,6 +271,7 @@ ensure_crtc_cursor_data (MetaCrtcKms *crtc_kms)
   if (!crtc_cursor_data)
     {
       crtc_cursor_data = g_new0 (CrtcCursorData, 1);
+      crtc_cursor_data->hw_state_invalidated = TRUE;
       meta_crtc_kms_set_cursor_renderer_private (crtc_kms,
                                                  crtc_cursor_data,
                                                  g_free);
@@ -275,15 +281,12 @@ ensure_crtc_cursor_data (MetaCrtcKms *crtc_kms)
 }
 
 static void
-set_crtc_cursor (MetaCursorRendererNative *native,
-                 MetaKmsUpdate            *kms_update,
-                 MetaCrtcKms              *crtc_kms,
-                 int                       x,
-                 int                       y,
-                 MetaCursorSprite         *cursor_sprite)
+assign_cursor_plane (MetaCursorRendererNative *native,
+                     MetaCrtcKms              *crtc_kms,
+                     int                       x,
+                     int                       y,
+                     MetaCursorSprite         *cursor_sprite)
 {
-  MetaCursorRendererNativePrivate *priv =
-    meta_cursor_renderer_native_get_instance_private (native);
   MetaCrtc *crtc = META_CRTC (crtc_kms);
   MetaCursorNativePrivate *cursor_priv = get_cursor_priv (cursor_sprite);
   MetaGpuKms *gpu_kms = META_GPU_KMS (meta_crtc_get_gpu (crtc));
@@ -303,6 +306,7 @@ set_crtc_cursor (MetaCursorRendererNative *native,
   CrtcCursorData *crtc_cursor_data;
   int cursor_hotspot_x;
   int cursor_hotspot_y;
+  MetaKmsUpdate *kms_update;
   MetaKmsPlaneAssignment *plane_assignment;
 
   if (cursor_gpu_state->pending_buffer_state == META_CURSOR_BUFFER_STATE_SET)
@@ -333,9 +337,12 @@ set_crtc_cursor (MetaCursorRendererNative *native,
   flags = META_KMS_ASSIGN_PLANE_FLAG_ALLOW_FAIL;
   crtc_cursor_data = ensure_crtc_cursor_data (crtc_kms);
   crtc_buffer = crtc_cursor_data->buffer;
-  if (!priv->hw_state_invalidated && buffer == crtc_buffer)
+  if (!crtc_cursor_data->hw_state_invalidated && buffer == crtc_buffer)
     flags |= META_KMS_ASSIGN_PLANE_FLAG_FB_UNCHANGED;
 
+  kms_update =
+    meta_kms_ensure_pending_update (meta_kms_device_get_kms (kms_device),
+                                    meta_kms_crtc_get_device (kms_crtc));
   plane_assignment = meta_kms_update_assign_plane (kms_update,
                                                    kms_crtc,
                                                    cursor_plane,
@@ -351,6 +358,10 @@ set_crtc_cursor (MetaCursorRendererNative *native,
                                                 cursor_hotspot_x,
                                                 cursor_hotspot_y);
 
+  meta_kms_update_add_result_listener (kms_update,
+                                       on_kms_update_result,
+                                       native);
+
   crtc_cursor_data->buffer = buffer;
 
   if (cursor_gpu_state->pending_buffer_state == META_CURSOR_BUFFER_STATE_SET)
@@ -361,35 +372,6 @@ set_crtc_cursor (MetaCursorRendererNative *native,
     }
 }
 
-static void
-unset_crtc_cursor (MetaCursorRendererNative *native,
-                   MetaKmsUpdate            *kms_update,
-                   MetaCrtcKms              *crtc_kms)
-{
-  MetaCursorRendererNativePrivate *priv =
-    meta_cursor_renderer_native_get_instance_private (native);
-  MetaKmsCrtc *kms_crtc;
-  MetaKmsDevice *kms_device;
-  MetaKmsPlane *cursor_plane;
-  MetaDrmBuffer *crtc_buffer;
-  CrtcCursorData *crtc_cursor_data;
-
-  crtc_buffer = meta_crtc_kms_get_cursor_renderer_private (crtc_kms);
-  if (!priv->hw_state_invalidated && !crtc_buffer)
-    return;
-
-  kms_crtc = meta_crtc_kms_get_kms_crtc (crtc_kms);
-  kms_device = meta_kms_crtc_get_device (kms_crtc);
-  cursor_plane = meta_kms_device_get_cursor_plane_for (kms_device, kms_crtc);
-
-  if (cursor_plane)
-    meta_kms_update_unassign_plane (kms_update, kms_crtc, cursor_plane);
-
-  crtc_cursor_data = meta_crtc_kms_get_cursor_renderer_private (crtc_kms);
-  if (crtc_cursor_data)
-    crtc_cursor_data->buffer = NULL;
-}
-
 static float
 calculate_cursor_crtc_sprite_scale (MetaCursorSprite   *cursor_sprite,
                                     MetaLogicalMonitor *logical_monitor)
@@ -405,139 +387,121 @@ calculate_cursor_crtc_sprite_scale (MetaCursorSprite   *cursor_sprite,
     }
 }
 
-typedef struct
-{
-  MetaCursorRendererNative *in_cursor_renderer_native;
-  MetaLogicalMonitor *in_logical_monitor;
-  graphene_rect_t in_local_cursor_rect;
-  MetaCursorSprite *in_cursor_sprite;
-
-  gboolean out_painted;
-} UpdateCrtcCursorData;
-
-static gboolean
-update_monitor_crtc_cursor (MetaMonitor         *monitor,
-                            MetaMonitorMode     *monitor_mode,
-                            MetaMonitorCrtcMode *monitor_crtc_mode,
-                            gpointer             user_data,
-                            GError             **error)
+static void
+set_crtc_cursor (MetaCursorRendererNative *cursor_renderer_native,
+                 MetaRendererView         *view,
+                 MetaCrtc                 *crtc,
+                 MetaCursorSprite         *cursor_sprite)
 {
-  UpdateCrtcCursorData *data = user_data;
-  MetaCursorRendererNative *cursor_renderer_native =
-    data->in_cursor_renderer_native;
-  MetaCursorRendererNativePrivate *priv =
-    meta_cursor_renderer_native_get_instance_private (cursor_renderer_native);
-  MetaCrtc *crtc;
-  MetaGpuKms *gpu_kms;
-  MetaKmsDevice *kms_device;
-  MetaKms *kms;
-  MetaKmsUpdate *kms_update;
+  MetaCursorRenderer *cursor_renderer =
+    META_CURSOR_RENDERER (cursor_renderer_native);
+  MetaOutput *output = meta_crtc_get_outputs (crtc)->data;
+  MetaMonitor *monitor = meta_output_get_monitor (output);
+  MetaLogicalMonitor *logical_monitor =
+    meta_monitor_get_logical_monitor (monitor);
+  const MetaCrtcConfig *crtc_config = meta_crtc_get_config (crtc);
+  graphene_rect_t rect;
+  graphene_rect_t local_crtc_rect;
+  graphene_rect_t local_cursor_rect;
+  float view_scale;
+  float crtc_cursor_x, crtc_cursor_y;
+  CoglTexture *texture;
+  int tex_width, tex_height;
+  float cursor_crtc_scale;
+  MetaRectangle cursor_rect;
   MetaMonitorTransform transform;
+  MetaMonitorTransform inverted_transform;
+  MetaMonitorMode *monitor_mode;
+  MetaMonitorCrtcMode *monitor_crtc_mode;
   const MetaCrtcModeInfo *crtc_mode_info;
-  graphene_rect_t scaled_crtc_rect;
-  float scale;
-  int crtc_x, crtc_y;
-  int crtc_width, crtc_height;
 
-  if (meta_is_stage_views_scaled ())
-    scale = meta_logical_monitor_get_scale (data->in_logical_monitor);
-  else
-    scale = 1.0;
+  view_scale = clutter_stage_view_get_scale (CLUTTER_STAGE_VIEW (view));
 
-  transform = meta_logical_monitor_get_transform (data->in_logical_monitor);
-  transform = meta_monitor_logical_to_crtc_transform (monitor, transform);
+  rect = meta_cursor_renderer_calculate_rect (cursor_renderer, cursor_sprite);
+  local_cursor_rect =
+    GRAPHENE_RECT_INIT (rect.origin.x - logical_monitor->rect.x,
+                        rect.origin.y - logical_monitor->rect.y,
+                        rect.size.width,
+                        rect.size.height);
 
-  meta_monitor_calculate_crtc_pos (monitor, monitor_mode,
-                                   monitor_crtc_mode->output,
-                                   transform,
-                                   &crtc_x, &crtc_y);
-
-  crtc_mode_info = meta_crtc_mode_get_info (monitor_crtc_mode->crtc_mode);
+  local_crtc_rect = crtc_config->layout;
+  graphene_rect_offset (&local_crtc_rect,
+                        -logical_monitor->rect.x,
+                        -logical_monitor->rect.y);
 
-  if (meta_monitor_transform_is_rotated (transform))
-    {
-      crtc_width = crtc_mode_info->height;
-      crtc_height = crtc_mode_info->width;
-    }
-  else
-    {
-      crtc_width = crtc_mode_info->width;
-      crtc_height = crtc_mode_info->height;
-    }
+  crtc_cursor_x = (local_cursor_rect.origin.x -
+                   local_crtc_rect.origin.x) * view_scale;
+  crtc_cursor_y = (local_cursor_rect.origin.y -
+                   local_crtc_rect.origin.y) * view_scale;
 
-  scaled_crtc_rect = (graphene_rect_t) {
-    .origin = {
-      .x = crtc_x / scale,
-      .y = crtc_y / scale
-    },
-    .size = {
-      .width = crtc_width / scale,
-      .height = crtc_height / scale
-    },
+  texture = meta_cursor_sprite_get_cogl_texture (cursor_sprite);
+  tex_width = cogl_texture_get_width (texture);
+  tex_height = cogl_texture_get_height (texture);
+
+  cursor_crtc_scale =
+    calculate_cursor_crtc_sprite_scale (cursor_sprite,
+                                        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)
   };
 
-  crtc = meta_output_get_assigned_crtc (monitor_crtc_mode->output);
-  gpu_kms = META_GPU_KMS (meta_crtc_get_gpu (crtc));
-  kms_device = meta_gpu_kms_get_kms_device (gpu_kms);
-  kms = meta_kms_device_get_kms (kms_device);
-  kms_update = meta_kms_ensure_pending_update (kms, kms_device);
+  transform = meta_logical_monitor_get_transform (logical_monitor);
+  transform = meta_monitor_logical_to_crtc_transform (monitor, transform);
 
-  if (priv->has_hw_cursor &&
-      graphene_rect_intersection (&scaled_crtc_rect,
-                                  &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,
-                                crtc_mode_info->width,
-                                crtc_mode_info->height,
-                                &cursor_rect);
-
-      set_crtc_cursor (data->in_cursor_renderer_native,
-                       kms_update,
+  inverted_transform = meta_monitor_transform_invert (transform);
+
+  monitor_mode = meta_monitor_get_current_mode (monitor);
+  monitor_crtc_mode = meta_monitor_get_crtc_mode_for_output (monitor,
+                                                             monitor_mode,
+                                                             output);
+  crtc_mode_info = meta_crtc_mode_get_info (monitor_crtc_mode->crtc_mode);
+  meta_rectangle_transform (&cursor_rect,
+                            inverted_transform,
+                            crtc_mode_info->width,
+                            crtc_mode_info->height,
+                            &cursor_rect);
+
+  assign_cursor_plane (cursor_renderer_native,
                        META_CRTC_KMS (crtc),
                        cursor_rect.x,
                        cursor_rect.y,
-                       data->in_cursor_sprite);
+                       cursor_sprite);
+}
 
-      data->out_painted = data->out_painted || TRUE;
-    }
-  else
+static void
+unset_crtc_cursor (MetaCursorRendererNative *native,
+                   MetaCrtc                 *crtc)
+{
+  MetaCrtcKms *crtc_kms = META_CRTC_KMS (crtc);
+  CrtcCursorData *crtc_cursor_data;
+  MetaKmsCrtc *kms_crtc;
+  MetaKmsDevice *kms_device;
+  MetaKmsPlane *cursor_plane;
+  MetaDrmBuffer *crtc_buffer;
+
+  crtc_cursor_data = ensure_crtc_cursor_data (crtc_kms);
+  crtc_buffer = crtc_cursor_data->buffer;
+  if (!crtc_cursor_data->hw_state_invalidated && !crtc_buffer)
+    return;
+
+  kms_crtc = meta_crtc_kms_get_kms_crtc (crtc_kms);
+  kms_device = meta_kms_crtc_get_device (kms_crtc);
+  cursor_plane = meta_kms_device_get_cursor_plane_for (kms_device, kms_crtc);
+
+  if (cursor_plane)
     {
-      unset_crtc_cursor (data->in_cursor_renderer_native,
-                         kms_update,
-                         META_CRTC_KMS (crtc));
+      MetaKms *kms = meta_kms_device_get_kms (kms_device);
+      MetaKmsUpdate *kms_update;
+
+      kms_update = meta_kms_ensure_pending_update (kms, kms_device);
+      meta_kms_update_unassign_plane (kms_update, kms_crtc, cursor_plane);
     }
 
-  return TRUE;
+  crtc_cursor_data->buffer = NULL;
 }
 
 static void
@@ -556,68 +520,61 @@ disable_hw_cursor_for_crtc (MetaKmsCrtc  *kms_crtc,
   cursor_renderer_gpu_data->hw_cursor_broken = TRUE;
 }
 
-static void
-update_hw_cursor (MetaCursorRendererNative *native,
-                  MetaCursorSprite         *cursor_sprite)
+void
+meta_cursor_renderer_native_prepare_frame (MetaCursorRendererNative *cursor_renderer_native,
+                                           MetaRendererView         *view)
 {
+  MetaCursorRenderer *cursor_renderer =
+    META_CURSOR_RENDERER (cursor_renderer_native);
   MetaCursorRendererNativePrivate *priv =
-    meta_cursor_renderer_native_get_instance_private (native);
-  MetaCursorRenderer *renderer = META_CURSOR_RENDERER (native);
+    meta_cursor_renderer_native_get_instance_private (cursor_renderer_native);
   MetaBackend *backend = priv->backend;
   MetaMonitorManager *monitor_manager =
     meta_backend_get_monitor_manager (backend);
-  GList *logical_monitors;
-  GList *l;
-  graphene_rect_t rect;
-  gboolean painted = FALSE;
+  MetaCrtc *crtc = meta_renderer_view_get_crtc (view);
+  MetaCursorSprite *cursor_sprite;
+  graphene_rect_t cursor_rect;
+  cairo_rectangle_int_t view_layout;
+  graphene_rect_t view_rect;
+  CrtcCursorData *crtc_cursor_data;
 
-  if (cursor_sprite)
-    rect = meta_cursor_renderer_calculate_rect (renderer, cursor_sprite);
-  else
-    rect = GRAPHENE_RECT_INIT_ZERO;
+  if (meta_monitor_manager_get_power_save_mode (monitor_manager) !=
+      META_POWER_SAVE_ON)
+    return;
 
-  logical_monitors =
-    meta_monitor_manager_get_logical_monitors (monitor_manager);
-  for (l = logical_monitors; l; l = l->next)
-    {
-      MetaLogicalMonitor *logical_monitor = l->data;
-      UpdateCrtcCursorData data;
-      GList *monitors;
-      GList *k;
-
-      data = (UpdateCrtcCursorData) {
-        .in_cursor_renderer_native = native,
-        .in_logical_monitor = logical_monitor,
-        .in_local_cursor_rect = (graphene_rect_t) {
-          .origin = {
-            .x = rect.origin.x - logical_monitor->rect.x,
-            .y = rect.origin.y - logical_monitor->rect.y
-          },
-          .size = rect.size
-        },
-        .in_cursor_sprite = cursor_sprite,
-      };
+  crtc_cursor_data = ensure_crtc_cursor_data (META_CRTC_KMS (crtc));
+  if (!crtc_cursor_data->hw_state_invalidated &&
+      !crtc_cursor_data->needs_sync_position)
+    return;
 
-      monitors = meta_logical_monitor_get_monitors (logical_monitor);
-      for (k = monitors; k; k = k->next)
-        {
-          MetaMonitor *monitor = k->data;
-          MetaMonitorMode *monitor_mode;
-
-          monitor_mode = meta_monitor_get_current_mode (monitor);
-          meta_monitor_mode_foreach_crtc (monitor, monitor_mode,
-                                          update_monitor_crtc_cursor,
-                                          &data,
-                                          NULL);
-        }
+  cursor_sprite = meta_cursor_renderer_get_cursor (cursor_renderer);
+  if (!cursor_sprite)
+    goto unset_cursor;
 
-      painted = painted || data.out_painted;
-    }
+  if (!priv->has_hw_cursor)
+    goto unset_cursor;
+
+  cursor_rect = meta_cursor_renderer_calculate_rect (cursor_renderer,
+                                                     cursor_sprite);
+  clutter_stage_view_get_layout (CLUTTER_STAGE_VIEW (view), &view_layout);
+  view_rect = GRAPHENE_RECT_INIT (view_layout.x, view_layout.y,
+                                  view_layout.width, view_layout.height);
+  if (!graphene_rect_intersection (&cursor_rect, &view_rect, NULL))
+    goto unset_cursor;
 
-  priv->hw_state_invalidated = FALSE;
+  set_crtc_cursor (cursor_renderer_native, view, crtc, cursor_sprite);
 
-  if (painted)
-    meta_cursor_renderer_emit_painted (renderer, cursor_sprite);
+  meta_cursor_renderer_emit_painted (cursor_renderer, cursor_sprite);
+
+  crtc_cursor_data->needs_sync_position = FALSE;
+  crtc_cursor_data->hw_state_invalidated = FALSE;
+  return;
+
+unset_cursor:
+  unset_crtc_cursor (cursor_renderer_native, crtc);
+
+  crtc_cursor_data = ensure_crtc_cursor_data (META_CRTC_KMS (crtc));
+  crtc_cursor_data->hw_state_invalidated = FALSE;
 }
 
 static gboolean
@@ -1074,6 +1031,29 @@ on_kms_update_result (const MetaKmsFeedback *kms_feedback,
     }
 }
 
+static void
+schedule_sync_position (MetaCursorRendererNative *cursor_renderer_native)
+{
+  MetaCursorRendererNativePrivate *priv =
+    meta_cursor_renderer_native_get_instance_private (cursor_renderer_native);
+  GList *l;
+
+  for (l = meta_backend_get_gpus (priv->backend); l; l = l->next)
+    {
+      MetaGpu *gpu = l->data;
+      GList *l_crtc;
+
+      for (l_crtc = meta_gpu_get_crtcs (gpu); l_crtc; l_crtc = l_crtc->next)
+        {
+          MetaCrtcKms *crtc_kms = META_CRTC_KMS (l_crtc->data);
+          CrtcCursorData *crtc_cursor_data;
+
+          crtc_cursor_data = ensure_crtc_cursor_data (crtc_kms);
+          crtc_cursor_data->needs_sync_position = TRUE;
+        }
+    }
+}
+
 static gboolean
 meta_cursor_renderer_native_update_cursor (MetaCursorRenderer *renderer,
                                            MetaCursorSprite   *cursor_sprite)
@@ -1081,10 +1061,7 @@ meta_cursor_renderer_native_update_cursor (MetaCursorRenderer *renderer,
   MetaCursorRendererNative *native = META_CURSOR_RENDERER_NATIVE (renderer);
   MetaCursorRendererNativePrivate *priv =
     meta_cursor_renderer_native_get_instance_private (native);
-  MetaRendererNative *renderer_native =
-    META_RENDERER_NATIVE (meta_backend_get_renderer (priv->backend));
-  MetaBackendNative *backend_native = META_BACKEND_NATIVE (priv->backend);
-  MetaKms *kms = meta_backend_native_get_kms (backend_native);
+  ClutterStage *stage = CLUTTER_STAGE (meta_backend_get_stage (priv->backend));
   g_autoptr (GList) gpus = NULL;
 
   if (cursor_sprite)
@@ -1097,43 +1074,9 @@ meta_cursor_renderer_native_update_cursor (MetaCursorRenderer *renderer,
   maybe_schedule_cursor_sprite_animation_frame (native, cursor_sprite);
 
   priv->has_hw_cursor = should_have_hw_cursor (renderer, cursor_sprite, gpus);
-  update_hw_cursor (native, cursor_sprite);
-
-  if (!meta_renderer_native_is_mode_set_pending (renderer_native))
-    {
-      GList *l;
 
-      for (l = meta_kms_get_devices (kms); l; l = l->next)
-        {
-          MetaKmsDevice *kms_device = l->data;
-          MetaKmsUpdateFlag flags;
-          g_autoptr (MetaKmsFeedback) kms_feedback = NULL;
-
-          flags = META_KMS_UPDATE_FLAG_NONE;
-          kms_feedback = meta_kms_post_pending_update_sync (kms,
-                                                            kms_device,
-                                                            flags);
-          on_kms_update_result (kms_feedback, renderer);
-        }
-    }
-  else
-    {
-      GList *l;
-
-      for (l = meta_kms_get_devices (kms); l; l = l->next)
-        {
-          MetaKmsDevice *kms_device = l->data;
-          MetaKmsUpdate *kms_update;
-
-          kms_update = meta_kms_get_pending_update (kms, kms_device);
-          if (!kms_update)
-            continue;
-
-          meta_kms_update_add_result_listener (kms_update,
-                                               on_kms_update_result,
-                                               renderer);
-        }
-    }
+  schedule_sync_position (native);
+  clutter_stage_schedule_update (stage);
 
   return (priv->has_hw_cursor ||
           !cursor_sprite ||
@@ -1779,8 +1722,23 @@ force_update_hw_cursor (MetaCursorRendererNative *native)
   MetaCursorRenderer *renderer = META_CURSOR_RENDERER (native);
   MetaCursorRendererNativePrivate *priv =
     meta_cursor_renderer_native_get_instance_private (native);
+  GList *l;
+
+  for (l = meta_backend_get_gpus (priv->backend); l; l = l->next)
+    {
+      MetaGpu *gpu = l->data;
+      GList *l_crtc;
+
+      for (l_crtc = meta_gpu_get_crtcs (gpu); l_crtc; l_crtc = l_crtc->next)
+        {
+          MetaCrtcKms *crtc_kms = META_CRTC_KMS (l_crtc->data);
+          CrtcCursorData *crtc_cursor_data;
+
+          crtc_cursor_data = ensure_crtc_cursor_data (crtc_kms);
+          crtc_cursor_data->hw_state_invalidated = TRUE;
+        }
+    }
 
-  priv->hw_state_invalidated = TRUE;
   meta_cursor_renderer_force_update (renderer);
 }
 
@@ -1863,7 +1821,6 @@ meta_cursor_renderer_native_new (MetaBackend        *backend,
                     G_CALLBACK (on_gpu_added_for_cursor), NULL);
 
   priv->backend = backend;
-  priv->hw_state_invalidated = TRUE;
 
   init_hw_cursor_support (cursor_renderer_native);
 
diff --git a/src/backends/native/meta-cursor-renderer-native.h 
b/src/backends/native/meta-cursor-renderer-native.h
index 26c698cda5..5113b96ce1 100644
--- a/src/backends/native/meta-cursor-renderer-native.h
+++ b/src/backends/native/meta-cursor-renderer-native.h
@@ -33,6 +33,9 @@ G_DECLARE_FINAL_TYPE (MetaCursorRendererNative, meta_cursor_renderer_native,
                       META, CURSOR_RENDERER_NATIVE,
                       MetaCursorRenderer)
 
+void meta_cursor_renderer_native_prepare_frame (MetaCursorRendererNative *cursor_renderer_native,
+                                                MetaRendererView         *view);
+
 MetaCursorRendererNative * meta_cursor_renderer_native_new (MetaBackend        *backend,
                                                             ClutterInputDevice *device);
 
diff --git a/src/backends/native/meta-renderer-native.c b/src/backends/native/meta-renderer-native.c
index 9efee2c1fe..f1b9c749b9 100644
--- a/src/backends/native/meta-renderer-native.c
+++ b/src/backends/native/meta-renderer-native.c
@@ -2345,12 +2345,6 @@ meta_renderer_native_create_dma_buf (CoglRenderer  *cogl_renderer,
   return NULL;
 }
 
-gboolean
-meta_renderer_native_is_mode_set_pending (MetaRendererNative *renderer_native)
-{
-  return renderer_native->pending_mode_set;
-}
-
 gboolean
 meta_onscreen_native_is_buffer_scanout_compatible (CoglOnscreen *onscreen,
                                                    uint32_t      drm_format,
@@ -3286,9 +3280,76 @@ meta_renderer_native_rebuild_views (MetaRenderer *renderer)
   meta_renderer_native_queue_modes_reset (META_RENDERER_NATIVE (renderer));
 }
 
+static void
+add_onscreen_frame_info (MetaCrtc *crtc)
+{
+  MetaGpu *gpu = meta_crtc_get_gpu (crtc);
+  MetaBackend *backend = meta_gpu_get_backend (gpu);
+  ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
+  MetaStageNative *stage_native =
+    meta_clutter_backend_native_get_stage_native (clutter_backend);
+  MetaRenderer *renderer = meta_backend_get_renderer (backend);
+  MetaRendererView *view = meta_renderer_get_view_for_crtc (renderer, crtc);
+
+  clutter_stage_cogl_add_onscreen_frame_info (CLUTTER_STAGE_COGL (stage_native),
+                                              CLUTTER_STAGE_VIEW (view));
+}
+
 void
-meta_renderer_native_finish_frame (MetaRendererNative *renderer_native)
+meta_renderer_native_finish_frame (MetaRendererNative *renderer_native,
+                                   MetaRendererView   *view,
+                                   ClutterFrame       *frame)
 {
+  MetaRenderer *renderer = META_RENDERER (renderer_native);
+  MetaBackend *backend = meta_renderer_get_backend (renderer);
+  MetaBackendNative *backend_native = META_BACKEND_NATIVE (backend);
+  MetaKms *kms = meta_backend_native_get_kms (backend_native);
+
+  if (!clutter_frame_has_result (frame))
+    {
+      MetaCrtc *crtc = meta_renderer_view_get_crtc (view);
+      MetaKmsCrtc *kms_crtc = meta_crtc_kms_get_kms_crtc (META_CRTC_KMS (crtc));
+      MetaKmsDevice *kms_device = meta_kms_crtc_get_device (kms_crtc);;
+      MetaKmsUpdateFlag flags;
+      MetaKmsUpdate *kms_update;
+      g_autoptr (MetaKmsFeedback) kms_feedback = NULL;
+      const GError *error;
+
+      kms_update = meta_kms_get_pending_update (kms, kms_device);
+      if (!kms_update)
+        {
+          clutter_frame_set_result (frame, CLUTTER_FRAME_RESULT_IDLE);
+          return;
+        }
+
+      meta_kms_update_add_page_flip_listener (kms_update,
+                                              kms_crtc,
+                                              &page_flip_listener_vtable,
+                                              g_object_ref (view));
+
+      flags = META_KMS_UPDATE_FLAG_NONE;
+      kms_feedback = meta_kms_post_pending_update_sync (kms,
+                                                        kms_device,
+                                                        flags);
+      switch (meta_kms_feedback_get_result (kms_feedback))
+        {
+        case META_KMS_FEEDBACK_PASSED:
+          add_onscreen_frame_info (crtc);
+          clutter_frame_set_result (frame,
+                                    CLUTTER_FRAME_RESULT_PENDING_PRESENTED);
+          break;
+        case META_KMS_FEEDBACK_FAILED:
+          clutter_frame_set_result (frame,
+                                    CLUTTER_FRAME_RESULT_IDLE);
+
+          error = meta_kms_feedback_get_error (kms_feedback);
+          if (!g_error_matches (error,
+                                G_IO_ERROR,
+                                G_IO_ERROR_PERMISSION_DENIED))
+            g_warning ("Failed to post KMS update: %s", error->message);
+          break;
+        }
+    }
 }
 
 static gboolean
diff --git a/src/backends/native/meta-renderer-native.h b/src/backends/native/meta-renderer-native.h
index e48712be83..786bd9d41b 100644
--- a/src/backends/native/meta-renderer-native.h
+++ b/src/backends/native/meta-renderer-native.h
@@ -53,14 +53,14 @@ struct gbm_device * meta_gbm_device_from_gpu (MetaGpuKms *gpu_kms);
 
 MetaGpuKms * meta_renderer_native_get_primary_gpu (MetaRendererNative *renderer_native);
 
-void meta_renderer_native_finish_frame (MetaRendererNative *renderer_native);
+void meta_renderer_native_finish_frame (MetaRendererNative *renderer_native,
+                                        MetaRendererView   *view,
+                                        ClutterFrame       *frame);
 
 void meta_renderer_native_reset_modes (MetaRendererNative *renderer_native);
 
 gboolean meta_renderer_native_use_modifiers (MetaRendererNative *renderer_native);
 
-gboolean meta_renderer_native_is_mode_set_pending (MetaRendererNative *renderer_native);
-
 gboolean meta_onscreen_native_is_buffer_scanout_compatible (CoglOnscreen *onscreen,
                                                             uint32_t      drm_format,
                                                             uint64_t      drm_modifier,
diff --git a/src/backends/native/meta-stage-native.c b/src/backends/native/meta-stage-native.c
index 2a29f93127..3b27c99303 100644
--- a/src/backends/native/meta-stage-native.c
+++ b/src/backends/native/meta-stage-native.c
@@ -27,6 +27,7 @@
 #include "backends/native/meta-stage-native.h"
 
 #include "backends/meta-backend-private.h"
+#include "backends/native/meta-cursor-renderer-native.h"
 #include "backends/native/meta-renderer-native.h"
 #include "meta/meta-backend.h"
 #include "meta/meta-monitor-manager.h"
@@ -105,6 +106,21 @@ meta_stage_native_get_views (ClutterStageWindow *stage_window)
   return meta_renderer_get_views (renderer);
 }
 
+static void
+meta_stage_native_prepare_frame (ClutterStageWindow *stage_window,
+                                 ClutterStageView   *stage_view,
+                                 ClutterFrame       *frame)
+{
+  MetaBackend *backend = meta_get_backend ();
+  MetaCursorRenderer *cursor_renderer =
+    meta_backend_get_cursor_renderer (backend);
+  MetaCursorRendererNative *cursor_renderer_native =
+    META_CURSOR_RENDERER_NATIVE (cursor_renderer);
+
+  meta_cursor_renderer_native_prepare_frame (cursor_renderer_native,
+                                             META_RENDERER_VIEW (stage_view));
+}
+
 static void
 meta_stage_native_finish_frame (ClutterStageWindow *stage_window,
                                 ClutterStageView   *stage_view,
@@ -113,10 +129,9 @@ meta_stage_native_finish_frame (ClutterStageWindow *stage_window,
   MetaBackend *backend = meta_get_backend ();
   MetaRenderer *renderer = meta_backend_get_renderer (backend);
 
-  meta_renderer_native_finish_frame (META_RENDERER_NATIVE (renderer));
-
-  if (!clutter_frame_has_result (frame))
-    clutter_frame_set_result (frame, CLUTTER_FRAME_RESULT_IDLE);
+  meta_renderer_native_finish_frame (META_RENDERER_NATIVE (renderer),
+                                     META_RENDERER_VIEW (stage_view),
+                                     frame);
 }
 
 static void
@@ -139,5 +154,6 @@ clutter_stage_window_iface_init (ClutterStageWindowInterface *iface)
   iface->can_clip_redraws = meta_stage_native_can_clip_redraws;
   iface->get_geometry = meta_stage_native_get_geometry;
   iface->get_views = meta_stage_native_get_views;
+  iface->prepare_frame = meta_stage_native_prepare_frame;
   iface->finish_frame = meta_stage_native_finish_frame;
 }


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