mirror of
https://github.com/brl/mutter.git
synced 2024-11-21 15:40:41 -05:00
clutter/actor: Always update last_paint_volumes during painting
It's currently possible that some last_paint_volumes don't get updated during a paint cycle, this can happen when a ClutterOffscreenEffect is used: The offscreen effect might skip painting the content and the children of an actor because it uses its own offscreened texture instead. This means the offscreen effect doesn't call clutter_actor_continue_paint(), and thus the the last_paint_volumes of the children won't be updated. Now one might think that isn't a problem, because as soon as a child changes it's size or position, the offscreened texture would get invalidated and clutter_actor_continue_paint() would get called. It's not that easy though: Because the last_paint_volume includes all the transformation matrices up to eye-coordinates, it has to be updated on any changes to matrices, which includes position/transformation changes to any actor up the hierarchy. Now that's where get into problems with the offscreen effect: In case of transformation changes to the offscreened actor or an actor up the hierarchy, the offscreened texture won't get invalidated (that makes sense, we can simply paint it transformed) and the last_paint_volumes won't get updated even though they should. This leaves us around with outdated last_paint_volumes where last_paint_volume_valid is still set to TRUE. It can cause issues with culling and clipped redraws. So fix that by ensuring that all children that would get painted by Clutter get their last_paint_volumes updated in case a ClutterEffect decided not to call clutter_actor_continue_paint(). This ignores the case where a paint() vfunc override does the same and doesn't call clutter_actor_paint() on children. Let's ignore this case for now, there shouldn't be any implementation which does that and ideally in a world that's painted solely by ClutterContent, we can get rid of that vfunc in the future. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1591>
This commit is contained in:
parent
0da8a49719
commit
0320649a1c
@ -844,6 +844,7 @@ struct _ClutterActorPrivate
|
||||
guint needs_paint_volume_update : 1;
|
||||
guint had_effects_on_last_paint_volume_update : 1;
|
||||
guint needs_update_stage_views : 1;
|
||||
guint children_painted : 1;
|
||||
};
|
||||
|
||||
enum
|
||||
@ -3586,6 +3587,30 @@ clutter_actor_paint_node (ClutterActor *actor,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
ensure_last_paint_volumes_updated (ClutterActor *self)
|
||||
{
|
||||
ClutterActorPrivate *priv = self->priv;
|
||||
ClutterActor *child;
|
||||
|
||||
/* Same entry checks as in clutter_actor_paint() */
|
||||
if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
|
||||
return;
|
||||
|
||||
if (!CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
|
||||
((priv->opacity_override >= 0) ?
|
||||
priv->opacity_override : priv->opacity) == 0)
|
||||
return;
|
||||
|
||||
if (!CLUTTER_ACTOR_IS_MAPPED (self))
|
||||
return;
|
||||
|
||||
_clutter_actor_update_last_paint_volume (self);
|
||||
|
||||
for (child = priv->first_child; child; child = child->priv->next_sibling)
|
||||
ensure_last_paint_volumes_updated (child);
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_actor_paint:
|
||||
* @self: A #ClutterActor
|
||||
@ -3791,8 +3816,28 @@ clutter_actor_paint (ClutterActor *self,
|
||||
if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES))
|
||||
_clutter_actor_draw_paint_volume (self, actor_node);
|
||||
|
||||
priv->children_painted = FALSE;
|
||||
|
||||
clutter_paint_node_paint (root_node, paint_context);
|
||||
|
||||
/* If an effect choose to not call clutter_actor_continue_paint()
|
||||
* (for example offscreen effects might just paint their cached
|
||||
* texture instead), the last_paint_volumes of the whole subtree
|
||||
* still need to be updated to adjust for any changes to their
|
||||
* eye-coordinates transformation matrices.
|
||||
*/
|
||||
if (!priv->children_painted)
|
||||
{
|
||||
if (!culling_inhibited &&
|
||||
!in_clone_paint () &&
|
||||
G_LIKELY ((clutter_paint_debug_flags &
|
||||
(CLUTTER_DEBUG_DISABLE_CULLING |
|
||||
CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)) !=
|
||||
(CLUTTER_DEBUG_DISABLE_CULLING |
|
||||
CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
|
||||
ensure_last_paint_volumes_updated (self);
|
||||
}
|
||||
|
||||
/* If we make it here then the actor has run through a complete
|
||||
paint run including all the effects so it's no longer dirty */
|
||||
priv->is_dirty = FALSE;
|
||||
@ -3835,6 +3880,8 @@ clutter_actor_continue_paint (ClutterActor *self,
|
||||
CoglFramebuffer *framebuffer;
|
||||
ClutterPaintNode *dummy;
|
||||
|
||||
priv->children_painted = TRUE;
|
||||
|
||||
/* XXX - this will go away in 2.0, when we can get rid of this
|
||||
* stuff and switch to a pure retained render tree of PaintNodes
|
||||
* for the entire frame, starting from the Stage; the paint()
|
||||
|
Loading…
Reference in New Issue
Block a user