diff --git a/clutter/clutter/clutter-damage-history.c b/clutter/clutter/clutter-damage-history.c
new file mode 100644
index 000000000..d5e86f1b7
--- /dev/null
+++ b/clutter/clutter/clutter-damage-history.c
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2007,2008,2009,2010,2011 Intel Corporation.
+ * Copyright (C) 2020 Red Hat Inc
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see .
+ */
+
+#include "clutter-build-config.h"
+
+#include "clutter-damage-history.h"
+
+#define DAMAGE_HISTORY_LENGTH 0x10
+
+struct _ClutterDamageHistory
+{
+ cairo_region_t *damages[DAMAGE_HISTORY_LENGTH];
+ int index;
+};
+
+ClutterDamageHistory *
+clutter_damage_history_new (void)
+{
+ ClutterDamageHistory *history;
+
+ history = g_new0 (ClutterDamageHistory, 1);
+
+ return history;
+}
+
+void
+clutter_damage_history_free (ClutterDamageHistory *history)
+{
+ int i;
+
+ for (i = 0; i < G_N_ELEMENTS (history->damages); i++)
+ g_clear_pointer (&history->damages[i], cairo_region_destroy);
+
+ g_free (history);
+}
+
+gboolean
+clutter_damage_history_is_age_valid (ClutterDamageHistory *history,
+ int age)
+{
+ if (age >= DAMAGE_HISTORY_LENGTH ||
+ age < 1)
+ return FALSE;
+
+ if (!clutter_damage_history_lookup (history, age))
+ return FALSE;
+
+ return TRUE;
+}
+
+void
+clutter_damage_history_record (ClutterDamageHistory *history,
+ const cairo_region_t *damage)
+{
+ g_clear_pointer (&history->damages[history->index], cairo_region_destroy);
+ history->damages[history->index] = cairo_region_copy (damage);
+}
+
+static inline int
+step_damage_index (int current,
+ int diff)
+{
+ return (current + diff) & (DAMAGE_HISTORY_LENGTH - 1);
+}
+
+void
+clutter_damage_history_step (ClutterDamageHistory *history)
+{
+ history->index = step_damage_index (history->index, 1);
+}
+
+const cairo_region_t *
+clutter_damage_history_lookup (ClutterDamageHistory *history,
+ int age)
+{
+ return history->damages[step_damage_index (history->index, -age)];
+}
diff --git a/clutter/clutter/clutter-damage-history.h b/clutter/clutter/clutter-damage-history.h
new file mode 100644
index 000000000..e29c3f1cb
--- /dev/null
+++ b/clutter/clutter/clutter-damage-history.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2007,2008,2009,2010,2011 Intel Corporation.
+ * Copyright (C) 2020 Red Hat Inc
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see .
+ */
+
+#ifndef CLUTTER_DAMAGE_HISTORY_H
+#define CLUTTER_DAMAGE_HISTORY_H
+
+#include
+#include
+
+typedef struct _ClutterDamageHistory ClutterDamageHistory;
+
+ClutterDamageHistory * clutter_damage_history_new (void);
+
+void clutter_damage_history_free (ClutterDamageHistory *history);
+
+gboolean clutter_damage_history_is_age_valid (ClutterDamageHistory *history,
+ int age);
+
+void clutter_damage_history_record (ClutterDamageHistory *history,
+ const cairo_region_t *damage);
+
+void clutter_damage_history_step (ClutterDamageHistory *history);
+
+const cairo_region_t * clutter_damage_history_lookup (ClutterDamageHistory *history,
+ int age);
+
+#endif /* CLUTTER_DAMAGE_HISTORY_H */
diff --git a/clutter/clutter/cogl/clutter-stage-cogl.c b/clutter/clutter/cogl/clutter-stage-cogl.c
index 2e2086c81..0552c04d0 100644
--- a/clutter/clutter/cogl/clutter-stage-cogl.c
+++ b/clutter/clutter/cogl/clutter-stage-cogl.c
@@ -38,6 +38,7 @@
#include "clutter-actor-private.h"
#include "clutter-backend-private.h"
+#include "clutter-damage-history.h"
#include "clutter-debug.h"
#include "clutter-event.h"
#include "clutter-enum-types.h"
@@ -51,13 +52,9 @@
typedef struct _ClutterStageViewCoglPrivate
{
- /*
- * List of previous damaged areas in stage view framebuffer coordinate space.
+ /* Damage history, in stage view render target framebuffer coordinate space.
*/
-#define DAMAGE_HISTORY_MAX 16
-#define DAMAGE_HISTORY(x) ((x) & (DAMAGE_HISTORY_MAX - 1))
- cairo_region_t * damage_history[DAMAGE_HISTORY_MAX];
- unsigned int damage_index;
+ ClutterDamageHistory *damage_history;
} ClutterStageViewCoglPrivate;
G_DEFINE_TYPE_WITH_PRIVATE (ClutterStageViewCogl, clutter_stage_view_cogl,
@@ -295,10 +292,7 @@ valid_buffer_age (ClutterStageViewCogl *view_cogl,
ClutterStageViewCoglPrivate *view_priv =
clutter_stage_view_cogl_get_instance_private (view_cogl);
- if (age <= 0)
- return FALSE;
-
- return age < MIN (view_priv->damage_index, DAMAGE_HISTORY_MAX);
+ return clutter_damage_history_is_age_valid (view_priv->damage_history, age);
}
static void
@@ -517,23 +511,6 @@ paint_stage (ClutterStageCogl *stage_cogl,
clutter_stage_view_after_paint (view, redraw_clip);
}
-static void
-fill_current_damage_history (ClutterStageView *view,
- cairo_region_t *damage)
-{
- ClutterStageViewCogl *view_cogl = CLUTTER_STAGE_VIEW_COGL (view);
- ClutterStageViewCoglPrivate *view_priv =
- clutter_stage_view_cogl_get_instance_private (view_cogl);
- cairo_region_t **current_fb_damage;
-
- current_fb_damage =
- &view_priv->damage_history[DAMAGE_HISTORY (view_priv->damage_index)];
-
- g_clear_pointer (current_fb_damage, cairo_region_destroy);
- *current_fb_damage = cairo_region_copy (damage);
- view_priv->damage_index++;
-}
-
static cairo_region_t *
transform_swap_region_to_onscreen (ClutterStageView *view,
cairo_region_t *swap_region)
@@ -666,23 +643,24 @@ clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window,
swap_with_damage = FALSE;
if (has_buffer_age)
{
- fill_current_damage_history (view, fb_clip_region);
+ clutter_damage_history_record (view_priv->damage_history,
+ fb_clip_region);
if (use_clipped_redraw)
{
cairo_region_t *fb_damage;
cairo_region_t *view_damage;
- int i;
+ int age;
fb_damage = cairo_region_create ();
- for (i = 1; i <= buffer_age; i++)
+ for (age = 1; age <= buffer_age; age++)
{
- int damage_index;
+ const cairo_region_t *old_damage;
- damage_index = DAMAGE_HISTORY (view_priv->damage_index - i - 1);
- cairo_region_union (fb_damage,
- view_priv->damage_history[damage_index]);
+ old_damage =
+ clutter_damage_history_lookup (view_priv->damage_history, age);
+ cairo_region_union (fb_damage, old_damage);
}
/* Update the fb clip region with the extra damage. */
@@ -705,6 +683,8 @@ clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window,
swap_with_damage = TRUE;
}
+
+ clutter_damage_history_step (view_priv->damage_history);
}
if (use_clipped_redraw)
@@ -891,12 +871,31 @@ _clutter_stage_cogl_init (ClutterStageCogl *stage)
stage->update_time = -1;
}
+static void
+clutter_stage_view_cogl_finalize (GObject *object)
+{
+ ClutterStageViewCogl *view_cogl = CLUTTER_STAGE_VIEW_COGL (object);
+ ClutterStageViewCoglPrivate *view_priv =
+ clutter_stage_view_cogl_get_instance_private (view_cogl);
+
+ clutter_damage_history_free (view_priv->damage_history);
+
+ G_OBJECT_CLASS (clutter_stage_view_cogl_parent_class)->finalize (object);
+}
+
static void
clutter_stage_view_cogl_init (ClutterStageViewCogl *view_cogl)
{
+ ClutterStageViewCoglPrivate *view_priv =
+ clutter_stage_view_cogl_get_instance_private (view_cogl);
+
+ view_priv->damage_history = clutter_damage_history_new ();
}
static void
clutter_stage_view_cogl_class_init (ClutterStageViewCoglClass *klass)
{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = clutter_stage_view_cogl_finalize;
}
diff --git a/clutter/clutter/meson.build b/clutter/clutter/meson.build
index f21d0e77c..179642740 100644
--- a/clutter/clutter/meson.build
+++ b/clutter/clutter/meson.build
@@ -114,6 +114,7 @@ clutter_sources = [
'clutter-constraint.c',
'clutter-container.c',
'clutter-content.c',
+ 'clutter-damage-history.c',
'clutter-deform-effect.c',
'clutter-desaturate-effect.c',
'clutter-effect.c',
@@ -185,6 +186,7 @@ clutter_private_headers = [
'clutter-bezier.h',
'clutter-constraint-private.h',
'clutter-content-private.h',
+ 'clutter-damage-history.h',
'clutter-debug.h',
'clutter-easing.h',
'clutter-effect-private.h',