stage: Keep queued actor redraw clip volumes separate

This aims to reduce the amount of pixels that have to be redrawed on the
screen on a clipped actor redraw in case using the union of two
different clips in a surface will substantially increase the redrawn
area.

This should not result in excessive memory consumption as callers of
`clutter_actor_queue_redraw_with_clip` are expected to ensure that the
redraw clip rectangles are adequately deduplicated.

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2965>
This commit is contained in:
msizanoen1 2023-04-17 17:51:58 +07:00 committed by Marge Bot
parent 17414fd242
commit 4048562961

View File

@ -77,8 +77,7 @@
typedef struct _QueueRedrawEntry typedef struct _QueueRedrawEntry
{ {
gboolean has_clip; GSList *clips;
ClutterPaintVolume clip;
} QueueRedrawEntry; } QueueRedrawEntry;
typedef struct _PickRecord typedef struct _PickRecord
@ -2542,52 +2541,39 @@ clutter_stage_queue_actor_redraw (ClutterStage *stage,
entry = g_hash_table_lookup (priv->pending_queue_redraws, actor); entry = g_hash_table_lookup (priv->pending_queue_redraws, actor);
if (entry) if (!entry)
{ {
/* Ignore all requests to queue a redraw for an actor if a full entry = g_new0 (QueueRedrawEntry, 1);
* (non-clipped) redraw of the actor has already been queued. */ g_hash_table_insert (priv->pending_queue_redraws,
if (!entry->has_clip) g_object_ref (actor), entry);
{ }
CLUTTER_NOTE (CLIPPING, "Bail from stage_queue_actor_redraw (%s): " else if (!entry->clips)
"Unclipped redraw of actor already queued", {
_clutter_actor_get_debug_name (actor)); CLUTTER_NOTE (CLIPPING, "Bail from stage_queue_actor_redraw (%s): "
return; "Unclipped redraw of actor already queued",
} _clutter_actor_get_debug_name (actor));
return;
}
/* If queuing a clipped redraw and a clipped redraw has /* If queuing a clipped redraw then append the latest
* previously been queued for this actor then combine the latest * clip to the clip list */
* clip together with the existing clip */ if (clip)
if (clip) {
clutter_paint_volume_union (&entry->clip, clip); ClutterPaintVolume *clip_pv = _clutter_paint_volume_new (actor);
else
{ _clutter_paint_volume_set_from_volume (clip_pv, clip);
clutter_paint_volume_free (&entry->clip); entry->clips = g_slist_prepend (entry->clips, clip_pv);
entry->has_clip = FALSE;
}
} }
else else
{ {
entry = g_new0 (QueueRedrawEntry, 1); g_clear_slist (&entry->clips, (GDestroyNotify) clutter_paint_volume_free);
if (clip)
{
entry->has_clip = TRUE;
_clutter_paint_volume_init_static (&entry->clip, actor);
_clutter_paint_volume_set_from_volume (&entry->clip, clip);
}
else
entry->has_clip = FALSE;
g_hash_table_insert (priv->pending_queue_redraws,
g_object_ref (actor), entry);
} }
} }
static void static void
free_queue_redraw_entry (QueueRedrawEntry *entry) free_queue_redraw_entry (QueueRedrawEntry *entry)
{ {
if (entry->has_clip) g_clear_slist (&entry->clips, (GDestroyNotify) clutter_paint_volume_free);
clutter_paint_volume_free (&entry->clip);
g_free (entry); g_free (entry);
} }
@ -2682,9 +2668,12 @@ clutter_stage_maybe_finish_queue_redraws (ClutterStage *stage)
_clutter_paint_volume_init_static (&old_actor_pv, NULL); _clutter_paint_volume_init_static (&old_actor_pv, NULL);
_clutter_paint_volume_init_static (&new_actor_pv, NULL); _clutter_paint_volume_init_static (&new_actor_pv, NULL);
if (entry->has_clip) if (entry->clips)
{ {
add_to_stage_clip (stage, &entry->clip); GSList *l;
for (l = entry->clips; l; l = l->next)
add_to_stage_clip (stage, l->data);
} }
else if (clutter_actor_get_redraw_clip (redraw_actor, else if (clutter_actor_get_redraw_clip (redraw_actor,
&old_actor_pv, &old_actor_pv,