[mutter] clutter/stage-view: Defer and accumulate redraw-clip on scanout



commit 550f09a5e7c24731eee6f232f84ec32af64dd5ca
Author: Robert Mader <robert mader posteo de>
Date:   Sat Jun 25 22:14:41 2022 +0200

    clutter/stage-view: Defer and accumulate redraw-clip on scanout
    
    When taking the scanout path we still want to clear the
    redraw-clip from the stage-view in order to ensure we skip
    frames in `handle_frame_clock_frame()` if no new redraw-clip
    was recorded.
    This was not done previously as the accumulated redraw-clip was
    needed for the next repaint, likely under the assumption that
    scheduling a scanout repeatedly would be computationally cost-free.
    This assumption does not hold in a VRR world.
    
    In order to archive both, an accumulated redraw-clip for the next
    paint and frame-skipping during scanout, introduce new API to defer
    and accumulate redraw-clips until the next repaint.
    
    Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2480>

 clutter/clutter/clutter-stage-view-private.h |  6 +++
 clutter/clutter/clutter-stage-view.c         | 71 ++++++++++++++++++++++++----
 src/backends/meta-stage-impl.c               |  7 ++-
 3 files changed, 73 insertions(+), 11 deletions(-)
---
diff --git a/clutter/clutter/clutter-stage-view-private.h b/clutter/clutter/clutter-stage-view-private.h
index 39d8601ea5..309dde4960 100644
--- a/clutter/clutter/clutter-stage-view-private.h
+++ b/clutter/clutter/clutter-stage-view-private.h
@@ -59,6 +59,12 @@ const cairo_region_t * clutter_stage_view_peek_redraw_clip (ClutterStageView *vi
 CLUTTER_EXPORT
 cairo_region_t * clutter_stage_view_take_redraw_clip (ClutterStageView *view);
 
+CLUTTER_EXPORT
+cairo_region_t * clutter_stage_view_take_accumulated_redraw_clip (ClutterStageView *view);
+
+CLUTTER_EXPORT
+void clutter_stage_view_accumulate_redraw_clip (ClutterStageView *view);
+
 CLUTTER_EXPORT
 CoglScanout * clutter_stage_view_take_scanout (ClutterStageView *view);
 
diff --git a/clutter/clutter/clutter-stage-view.c b/clutter/clutter/clutter-stage-view.c
index 2e47237f0a..22c7647996 100644
--- a/clutter/clutter/clutter-stage-view.c
+++ b/clutter/clutter/clutter-stage-view.c
@@ -78,6 +78,8 @@ typedef struct _ClutterStageViewPrivate
 
   gboolean has_redraw_clip;
   cairo_region_t *redraw_clip;
+  gboolean has_accumulated_redraw_clip;
+  cairo_region_t *accumulated_redraw_clip;
 
   float refresh_rate;
   int64_t vblank_duration_us;
@@ -920,6 +922,23 @@ clutter_stage_view_get_offscreen_transformation_matrix (ClutterStageView  *view,
   view_class->get_offscreen_transformation_matrix (view, matrix);
 }
 
+static void
+maybe_mark_full_redraw (ClutterStageView  *view,
+                        cairo_region_t   **region)
+{
+  ClutterStageViewPrivate *priv =
+    clutter_stage_view_get_instance_private (view);
+
+  if (cairo_region_num_rectangles (*region) == 1)
+    {
+      cairo_rectangle_int_t region_extents;
+
+      cairo_region_get_extents (*region, &region_extents);
+      if (clutter_util_rectangle_equal (&priv->layout, &region_extents))
+        g_clear_pointer (region, cairo_region_destroy);
+    }
+}
+
 void
 clutter_stage_view_add_redraw_clip (ClutterStageView            *view,
                                     const cairo_rectangle_int_t *clip)
@@ -948,15 +967,7 @@ clutter_stage_view_add_redraw_clip (ClutterStageView            *view,
   else
     {
       cairo_region_union_rectangle (priv->redraw_clip, clip);
-
-      if (cairo_region_num_rectangles (priv->redraw_clip) == 1)
-        {
-          cairo_rectangle_int_t redraw_clip_extents;
-
-          cairo_region_get_extents (priv->redraw_clip, &redraw_clip_extents);
-          if (clutter_util_rectangle_equal (&priv->layout, &redraw_clip_extents))
-            g_clear_pointer (&priv->redraw_clip, cairo_region_destroy);
-        }
+      maybe_mark_full_redraw (view, &priv->redraw_clip);
     }
 
   priv->has_redraw_clip = TRUE;
@@ -1000,6 +1011,47 @@ clutter_stage_view_take_redraw_clip (ClutterStageView *view)
   return g_steal_pointer (&priv->redraw_clip);
 }
 
+cairo_region_t *
+clutter_stage_view_take_accumulated_redraw_clip (ClutterStageView *view)
+{
+  ClutterStageViewPrivate *priv =
+    clutter_stage_view_get_instance_private (view);
+
+  g_return_val_if_fail (priv->has_redraw_clip, NULL);
+
+  clutter_stage_view_accumulate_redraw_clip (view);
+
+  priv->has_accumulated_redraw_clip = FALSE;
+  return g_steal_pointer (&priv->accumulated_redraw_clip);
+}
+
+void
+clutter_stage_view_accumulate_redraw_clip (ClutterStageView *view)
+{
+  ClutterStageViewPrivate *priv =
+    clutter_stage_view_get_instance_private (view);
+
+  g_return_if_fail (priv->has_redraw_clip);
+
+  if (priv->redraw_clip && priv->accumulated_redraw_clip)
+    {
+      cairo_region_union (priv->accumulated_redraw_clip, priv->redraw_clip);
+      maybe_mark_full_redraw (view, &priv->accumulated_redraw_clip);
+    }
+  else if (priv->redraw_clip && !priv->has_accumulated_redraw_clip)
+    {
+      priv->accumulated_redraw_clip = g_steal_pointer (&priv->redraw_clip);
+    }
+  else
+    {
+      g_clear_pointer (&priv->accumulated_redraw_clip, cairo_region_destroy);
+    }
+
+  g_clear_pointer (&priv->redraw_clip, cairo_region_destroy);
+  priv->has_accumulated_redraw_clip = TRUE;
+  priv->has_redraw_clip = FALSE;
+}
+
 static void
 clutter_stage_default_get_offscreen_transformation_matrix (ClutterStageView  *view,
                                                            graphene_matrix_t *matrix)
@@ -1400,6 +1452,7 @@ clutter_stage_view_dispose (GObject *object)
   g_clear_object (&priv->offscreen);
   g_clear_pointer (&priv->offscreen_pipeline, cogl_object_unref);
   g_clear_pointer (&priv->redraw_clip, cairo_region_destroy);
+  g_clear_pointer (&priv->accumulated_redraw_clip, cairo_region_destroy);
   g_clear_pointer (&priv->frame_clock, clutter_frame_clock_destroy);
 
   G_OBJECT_CLASS (clutter_stage_view_parent_class)->dispose (object);
diff --git a/src/backends/meta-stage-impl.c b/src/backends/meta-stage-impl.c
index c45aaf852e..d562603c33 100644
--- a/src/backends/meta-stage-impl.c
+++ b/src/backends/meta-stage-impl.c
@@ -473,7 +473,7 @@ meta_stage_impl_redraw_view_primary (MetaStageImpl    *stage_impl,
     COGL_IS_ONSCREEN (onscreen) &&
     cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_BUFFER_AGE);
 
-  redraw_clip = clutter_stage_view_take_redraw_clip (stage_view);
+  redraw_clip = clutter_stage_view_take_accumulated_redraw_clip (stage_view);
 
   /* NB: a NULL redraw clip == full stage redraw */
   if (!redraw_clip)
@@ -725,7 +725,10 @@ meta_stage_impl_redraw_view (ClutterStageWindow *stage_window,
                                         scanout,
                                         frame,
                                         &error))
-        return;
+        {
+          clutter_stage_view_accumulate_redraw_clip (stage_view);
+          return;
+        }
 
       if (!g_error_matches (error,
                             COGL_SCANOUT_ERROR,


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