clutter/actor: Cache transformations applied using apply_transform vfunc

If we want to invalidate the stage-views list reliably on changes to the
actors transformation matrices, we also need to get notified about
changes to the custom transformations applied using the
apply_transform() vfunc.

So provide a new API that allows invalidating the transformation matrix
for actors implementing custom transformations, too. This in turn allows
us to cache the matrix applied using the apply_transform() vfunc by
moving responsibility of keeping track of the caching from
clutter_actor_real_apply_transform() to
_clutter_actor_apply_modelview_transform().

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1343
This commit is contained in:
Jonas Dreßler 2020-03-12 12:13:53 +01:00
parent c5159e3184
commit 64304b0b68
4 changed files with 48 additions and 23 deletions

View File

@ -3034,14 +3034,9 @@ clutter_actor_real_apply_transform (ClutterActor *self,
ClutterMatrix *matrix)
{
ClutterActorPrivate *priv = self->priv;
CoglMatrix *transform = &priv->transform;
const ClutterTransformInfo *info;
float pivot_x = 0.f, pivot_y = 0.f;
/* we already have a cached transformation */
if (priv->transform_valid)
goto multiply_and_return;
info = _clutter_actor_get_transform_info_or_defaults (self);
/* compute the pivot point given the allocated size */
@ -3067,10 +3062,10 @@ clutter_actor_real_apply_transform (ClutterActor *self,
const ClutterTransformInfo *parent_info;
parent_info = _clutter_actor_get_transform_info_or_defaults (priv->parent);
clutter_matrix_init_from_matrix (transform, &(parent_info->child_transform));
clutter_matrix_init_from_matrix (matrix, &(parent_info->child_transform));
}
else
clutter_matrix_init_identity (transform);
clutter_matrix_init_identity (matrix);
/* if we have an overriding transformation, we use that, and get out */
if (info->transform_set)
@ -3079,11 +3074,11 @@ clutter_actor_real_apply_transform (ClutterActor *self,
* translations, since :transform is relative to the actor's coordinate
* space, and to the pivot point
*/
cogl_matrix_translate (transform,
cogl_matrix_translate (matrix,
priv->allocation.x1 + pivot_x,
priv->allocation.y1 + pivot_y,
info->pivot_z);
cogl_matrix_multiply (transform, transform, &info->transform);
cogl_matrix_multiply (matrix, matrix, &info->transform);
goto roll_back_pivot;
}
@ -3091,7 +3086,7 @@ clutter_actor_real_apply_transform (ClutterActor *self,
* of decomposing the pivot and translation info separate operations,
* we just compose everything into a single translation
*/
cogl_matrix_translate (transform,
cogl_matrix_translate (matrix,
priv->allocation.x1 + pivot_x + info->translation.x,
priv->allocation.y1 + pivot_y + info->translation.y,
info->z_position + info->pivot_z + info->translation.z);
@ -3108,27 +3103,21 @@ clutter_actor_real_apply_transform (ClutterActor *self,
* code we use when interpolating transformations
*/
if (info->scale_x != 1.0 || info->scale_y != 1.0 || info->scale_z != 1.0)
cogl_matrix_scale (transform, info->scale_x, info->scale_y, info->scale_z);
cogl_matrix_scale (matrix, info->scale_x, info->scale_y, info->scale_z);
if (info->rz_angle)
cogl_matrix_rotate (transform, info->rz_angle, 0, 0, 1.0);
cogl_matrix_rotate (matrix, info->rz_angle, 0, 0, 1.0);
if (info->ry_angle)
cogl_matrix_rotate (transform, info->ry_angle, 0, 1.0, 0);
cogl_matrix_rotate (matrix, info->ry_angle, 0, 1.0, 0);
if (info->rx_angle)
cogl_matrix_rotate (transform, info->rx_angle, 1.0, 0, 0);
cogl_matrix_rotate (matrix, info->rx_angle, 1.0, 0, 0);
roll_back_pivot:
/* roll back the pivot translation */
if (pivot_x != 0.f || pivot_y != 0.f || info->pivot_z != 0.f)
cogl_matrix_translate (transform, -pivot_x, -pivot_y, -info->pivot_z);
/* we have a valid modelview */
priv->transform_valid = TRUE;
multiply_and_return:
cogl_matrix_multiply (matrix, matrix, &priv->transform);
cogl_matrix_translate (matrix, -pivot_x, -pivot_y, -info->pivot_z);
}
/* Applies the transforms associated with this actor to the given
@ -3137,7 +3126,17 @@ void
_clutter_actor_apply_modelview_transform (ClutterActor *self,
ClutterMatrix *matrix)
{
CLUTTER_ACTOR_GET_CLASS (self)->apply_transform (self, matrix);
ClutterActorPrivate *priv = self->priv;
if (priv->transform_valid)
goto out;
CLUTTER_ACTOR_GET_CLASS (self)->apply_transform (self, &priv->transform);
priv->transform_valid = TRUE;
out:
cogl_matrix_multiply (matrix, matrix, &priv->transform);
}
/*
@ -19739,3 +19738,20 @@ clutter_actor_queue_immediate_relayout (ClutterActor *self)
if (stage)
clutter_stage_set_actor_needs_immediate_relayout (stage);
}
/**
* clutter_actor_invalidate_transform:
* @self: A #ClutterActor
*
* Invalidate the cached transformation matrix of @self.
* This is needed for implementations overriding the apply_transform()
* vfunc and has to be called if the matrix returned by apply_transform()
* would change.
*/
void
clutter_actor_invalidate_transform (ClutterActor *self)
{
g_return_if_fail (CLUTTER_IS_ACTOR (self));
self->priv->transform_valid = FALSE;
}

View File

@ -178,7 +178,10 @@ struct _ClutterActor
* implementation.
* @apply_transform: virtual function, used when applying the transformations
* to an actor before painting it or when transforming coordinates or
* the allocation; it must chain up to the parent's implementation
* the allocation; if the transformation calculated by this function may
* have changed, the cached transformation must be invalidated by calling
* clutter_actor_invalidate_transform(); it must chain up to the parent's
* implementation
* @parent_set: signal class handler for the #ClutterActor::parent-set
* @destroy: signal class handler for #ClutterActor::destroy. It must
* chain up to the parent's implementation
@ -918,6 +921,9 @@ void clutter_actor_pick_box (ClutterActor *self,
CLUTTER_EXPORT
GList * clutter_actor_peek_stage_views (ClutterActor *self);
CLUTTER_EXPORT
void clutter_actor_invalidate_transform (ClutterActor *self);
G_END_DECLS
#endif /* __CLUTTER_ACTOR_H__ */

View File

@ -262,6 +262,7 @@ clutter_clone_allocate (ClutterActor *self,
{
priv->x_scale = x_scale;
priv->y_scale = y_scale;
clutter_actor_invalidate_transform (CLUTTER_ACTOR (self));
}
#if 0

View File

@ -2905,6 +2905,8 @@ clutter_stage_update_view_perspective (ClutterStage *stage)
z_2d,
priv->viewport[2],
priv->viewport[3]);
clutter_actor_invalidate_transform (CLUTTER_ACTOR (stage));
}
void