[mutter] clutter/actor: Add API to get the stage-views an actor is painted on



commit 675a97d58e3d4602a7905d49fe06c7b2ca60feea
Author: Jonas Dreßler <verdre v0yd nl>
Date:   Fri Apr 10 00:34:49 2020 +0200

    clutter/actor: Add API to get the stage-views an actor is painted on
    
    There are certain rendering techniques and optimizations, for example
    the unredirection of non-fullscreen windows, where information about the
    output/stage-view an actor is on is needed to determine whether the
    optimization can be enabled.
    
    So add a new method to ClutterActor that allows listing the stage-views
    the actor is being painted on: clutter_actor_peek_stage_views()
    
    With the way Clutter works, the only point where we can reliably get
    this information is during or right before the paint phase, when the
    layout phase of the stage has been completed and no more changes to the
    actors transformation matrices happen. So to get the stage views the
    actor is on, introduce a new step that's done on every master clock tick
    between layout and paint cycle: Traversing through the actor tree and
    updating the stage-views the mapped actors are going to be painted on.
    
    We're doing this in a separate step instead of inside
    clutter_actor_paint() itself for a few reasons: It keeps the code
    separate from the painting code, making profiling easier and issues
    easier to track down (hopefully), it allows for a new
    "stage-views-changed" signal that doesn't interfere with painting, and
    finally, it will make it very easy to update the resource scales in the
    same step in the future.
    
    Currently, this list is only invalidated on allocation changes of
    actors, but not on changes to the transformation matrices. That's
    because there's no proper API to invalidate the transformation matrices
    ClutterActor implementations can apply through the apply_transform()
    vfunc.
    
    https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1196

 clutter/clutter/clutter-actor-private.h |   2 +
 clutter/clutter/clutter-actor.c         | 114 +++++++++++++++++++++++++++++++-
 clutter/clutter/clutter-actor.h         |   3 +
 clutter/clutter/clutter-stage.c         |  12 ++++
 4 files changed, 129 insertions(+), 2 deletions(-)
---
diff --git a/clutter/clutter/clutter-actor-private.h b/clutter/clutter/clutter-actor-private.h
index 3b6a4153bd..ed398bf210 100644
--- a/clutter/clutter/clutter-actor-private.h
+++ b/clutter/clutter/clutter-actor-private.h
@@ -321,6 +321,8 @@ gboolean                        _clutter_actor_get_real_resource_scale
 ClutterPaintNode *              clutter_actor_create_texture_paint_node                 (ClutterActor *self,
                                                                                          CoglTexture  
*texture);
 
+void clutter_actor_update_stage_views (ClutterActor *self);
+
 G_END_DECLS
 
 #endif /* __CLUTTER_ACTOR_PRIVATE_H__ */
diff --git a/clutter/clutter/clutter-actor.c b/clutter/clutter/clutter-actor.c
index 5ea4cc1c9e..1d3f98d415 100644
--- a/clutter/clutter/clutter-actor.c
+++ b/clutter/clutter/clutter-actor.c
@@ -813,6 +813,8 @@ struct _ClutterActorPrivate
   gulong font_changed_id;
   gulong layout_changed_id;
 
+  GList *stage_views;
+
   /* bitfields: KEEP AT THE END */
 
   /* fixed position and sizes */
@@ -855,6 +857,7 @@ struct _ClutterActorPrivate
   guint had_effects_on_last_paint_volume_update : 1;
   guint needs_compute_resource_scale : 1;
   guint absolute_origin_changed     : 1;
+  guint needs_update_stage_views    : 1;
 };
 
 enum
@@ -2565,6 +2568,7 @@ static void
 absolute_allocation_changed (ClutterActor *actor)
 {
   actor->priv->needs_compute_resource_scale = TRUE;
+  actor->priv->needs_update_stage_views = TRUE;
 }
 
 static ClutterActorTraverseVisitFlags
@@ -4282,6 +4286,7 @@ typedef enum
   REMOVE_CHILD_FLUSH_QUEUE        = 1 << 4,
   REMOVE_CHILD_NOTIFY_FIRST_LAST  = 1 << 5,
   REMOVE_CHILD_STOP_TRANSITIONS   = 1 << 6,
+  REMOVE_CHILD_CLEAR_STAGE_VIEWS  = 1 << 7,
 
   /* default flags for public API */
   REMOVE_CHILD_DEFAULT_FLAGS      = REMOVE_CHILD_STOP_TRANSITIONS |
@@ -4290,14 +4295,16 @@ typedef enum
                                     REMOVE_CHILD_EMIT_ACTOR_REMOVED |
                                     REMOVE_CHILD_CHECK_STATE |
                                     REMOVE_CHILD_FLUSH_QUEUE |
-                                    REMOVE_CHILD_NOTIFY_FIRST_LAST,
+                                    REMOVE_CHILD_NOTIFY_FIRST_LAST |
+                                    REMOVE_CHILD_CLEAR_STAGE_VIEWS,
 
   /* flags for legacy/deprecated API */
   REMOVE_CHILD_LEGACY_FLAGS       = REMOVE_CHILD_STOP_TRANSITIONS |
                                     REMOVE_CHILD_CHECK_STATE |
                                     REMOVE_CHILD_FLUSH_QUEUE |
                                     REMOVE_CHILD_EMIT_PARENT_SET |
-                                    REMOVE_CHILD_NOTIFY_FIRST_LAST
+                                    REMOVE_CHILD_NOTIFY_FIRST_LAST |
+                                    REMOVE_CHILD_CLEAR_STAGE_VIEWS
 } ClutterActorRemoveChildFlags;
 
 /*< private >
@@ -4319,6 +4326,7 @@ clutter_actor_remove_child_internal (ClutterActor                 *self,
   gboolean notify_first_last;
   gboolean was_mapped;
   gboolean stop_transitions;
+  gboolean clear_stage_views;
   GObject *obj;
 
   if (self == child)
@@ -4335,6 +4343,7 @@ clutter_actor_remove_child_internal (ClutterActor                 *self,
   flush_queue = (flags & REMOVE_CHILD_FLUSH_QUEUE) != 0;
   notify_first_last = (flags & REMOVE_CHILD_NOTIFY_FIRST_LAST) != 0;
   stop_transitions = (flags & REMOVE_CHILD_STOP_TRANSITIONS) != 0;
+  clear_stage_views = (flags & REMOVE_CHILD_CLEAR_STAGE_VIEWS) != 0;
 
   obj = G_OBJECT (self);
   g_object_freeze_notify (obj);
@@ -4408,6 +4417,13 @@ clutter_actor_remove_child_internal (ClutterActor                 *self,
       clutter_actor_queue_compute_expand (self);
     }
 
+  /* Only actors which are attached to a stage get notified about changes
+   * to the stage views, so make sure all the stage-views lists are
+   * cleared as the child and its children leave the actor tree.
+   */
+  if (clear_stage_views)
+    clutter_actor_clear_stage_views_recursive (child);
+
   if (emit_parent_set && !CLUTTER_ACTOR_IN_DESTRUCTION (child))
     {
       child->priv->needs_compute_resource_scale = TRUE;
@@ -6080,6 +6096,8 @@ clutter_actor_dispose (GObject *object)
       priv->clones = NULL;
     }
 
+  g_clear_pointer (&priv->stage_views, g_list_free);
+
   G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
 }
 
@@ -8634,6 +8652,7 @@ clutter_actor_init (ClutterActor *self)
   priv->needs_allocation = TRUE;
   priv->needs_paint_volume_update = TRUE;
   priv->needs_compute_resource_scale = TRUE;
+  priv->needs_update_stage_views = TRUE;
 
   priv->cached_width_age = 1;
   priv->cached_height_age = 1;
@@ -17521,7 +17540,11 @@ clear_stage_views_cb (ClutterActor *actor,
                       int           depth,
                       gpointer      user_data)
 {
+  actor->priv->needs_update_stage_views = TRUE;
   actor->priv->needs_compute_resource_scale = TRUE;
+
+  g_clear_pointer (&actor->priv->stage_views, g_list_free);
+
   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
 }
 
@@ -17622,6 +17645,93 @@ clutter_actor_get_resource_scale (ClutterActor *self,
   return FALSE;
 }
 
+static void
+update_stage_views (ClutterActor *self)
+{
+  ClutterActorPrivate *priv = self->priv;
+  ClutterStage *stage;
+  graphene_rect_t bounding_rect;
+
+  g_clear_pointer (&priv->stage_views, g_list_free);
+
+  if (priv->needs_allocation)
+    {
+      g_warning ("Can't update stage views actor %s is on because it needs an "
+                 "allocation.", _clutter_actor_get_debug_name (self));
+      return;
+    }
+
+  stage = CLUTTER_STAGE (_clutter_actor_get_stage_internal (self));
+  g_return_if_fail (stage);
+
+  clutter_actor_get_transformed_position (self,
+                                          &bounding_rect.origin.x,
+                                          &bounding_rect.origin.y);
+  clutter_actor_get_transformed_size (self,
+                                      &bounding_rect.size.width,
+                                      &bounding_rect.size.height);
+
+  if (bounding_rect.size.width == 0.0 ||
+      bounding_rect.size.height == 0.0)
+    return;
+
+  priv->stage_views = clutter_stage_get_views_for_rect (stage,
+                                                        &bounding_rect);
+}
+
+void
+clutter_actor_update_stage_views (ClutterActor *self)
+{
+  ClutterActorPrivate *priv = self->priv;
+  ClutterActor *child;
+
+  if (!CLUTTER_ACTOR_IS_MAPPED (self) ||
+      CLUTTER_ACTOR_IN_DESTRUCTION (self))
+    return;
+
+  if (priv->needs_update_stage_views)
+    {
+      update_stage_views (self);
+
+      priv->needs_update_stage_views = FALSE;
+    }
+
+  for (child = priv->first_child; child; child = child->priv->next_sibling)
+    clutter_actor_update_stage_views (child);
+}
+
+/**
+ * clutter_actor_peek_stage_views:
+ * @self: A #ClutterActor
+ *
+ * Retrieves the list of #ClutterStageView<!-- -->s the actor is being
+ * painted on.
+ *
+ * If this function is called during the paint cycle, the list is guaranteed
+ * to be up-to-date, if called outside the paint cycle, the list will
+ * contain the views the actor was painted on last.
+ *
+ * The list returned by this function is not updated when the actors
+ * visibility changes: If an actor gets hidden and is not being painted
+ * anymore, this function will return the list of views the actor was
+ * painted on last.
+ *
+ * If an actor is not attached to a stage (realized), this function will
+ * always return an empty list.
+ *
+ * Returns: (transfer none) (element-type Clutter.StageView): The list of
+ *   #ClutterStageView<!-- -->s the actor is being painted on. The list and
+ *   its contents are owned by the #ClutterActor and the list may not be
+ *   freed or modified.
+ */
+GList *
+clutter_actor_peek_stage_views (ClutterActor *self)
+{
+  g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
+
+  return self->priv->stage_views;
+}
+
 /**
  * clutter_actor_has_overlaps:
  * @self: A #ClutterActor
diff --git a/clutter/clutter/clutter-actor.h b/clutter/clutter/clutter-actor.h
index b5d4b7845e..616e801699 100644
--- a/clutter/clutter/clutter-actor.h
+++ b/clutter/clutter/clutter-actor.h
@@ -919,6 +919,9 @@ void clutter_actor_pick_box (ClutterActor          *self,
                              ClutterPickContext    *pick_context,
                              const ClutterActorBox *box);
 
+CLUTTER_EXPORT
+GList * clutter_actor_peek_stage_views (ClutterActor *self);
+
 G_END_DECLS
 
 #endif /* __CLUTTER_ACTOR_H__ */
diff --git a/clutter/clutter/clutter-stage.c b/clutter/clutter/clutter-stage.c
index 5326b1cc26..ff079c1adc 100644
--- a/clutter/clutter/clutter-stage.c
+++ b/clutter/clutter/clutter-stage.c
@@ -1469,6 +1469,14 @@ _clutter_stage_check_updated_pointers (ClutterStage *stage)
   return updating;
 }
 
+static void
+update_actor_stage_views (ClutterStage *stage)
+{
+  ClutterActor *actor = CLUTTER_ACTOR (stage);
+
+  clutter_actor_update_stage_views (actor);
+}
+
 /**
  * _clutter_stage_do_update:
  * @stage: A #ClutterStage
@@ -1516,6 +1524,10 @@ _clutter_stage_do_update (ClutterStage *stage)
   if (stage_was_relayout)
     pointers = _clutter_stage_check_updated_pointers (stage);
 
+  COGL_TRACE_BEGIN (ClutterStageUpdateActorStageViews, "Actor stage-views");
+  update_actor_stage_views (stage);
+  COGL_TRACE_END (ClutterStageUpdateActorStageViews);
+
   COGL_TRACE_BEGIN (ClutterStagePaint, "Paint");
 
   clutter_stage_maybe_finish_queue_redraws (stage);


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