summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJasper St. Pierre <jstpierre@mecheye.net>2013-11-21 15:25:08 -0500
committerJasper St. Pierre <jstpierre@mecheye.net>2013-11-25 15:21:36 -0500
commit74e43a470268e16f2ee1e3bd69cf39e10c65cc0a (patch)
treeec8e2ebe583ec8f36841e38f15816377a8472011
parent0764b2058ad3686ffd910065d8accfa6ecccddc7 (diff)
downloadmutter-74e43a470268e16f2ee1e3bd69cf39e10c65cc0a.tar.gz
cullable: Turn cull_out / reset_culling into a separate interface
Instead of hardcoded knowledge of certain classes in MetaWindowGroup, create a generic interface that all actors can implement to get parts of their regions culled out during redraw, without needing any special knowledge of how to handle a specific actor. The names now are a bit suspect. MetaBackgroundGroup is a simple MetaCullable that knows how to cull children, and MetaWindowGroup is the "toplevel" cullable that computes the initial two regions. A future cleanup here could be to merge MetaWindowGroup / MetaBackgroundGroup so that we only have a generic MetaSimpleCullable, and move the "toplevel" cullability to be a MetaCullableToplevel. https://bugzilla.gnome.org/show_bug.cgi?id=714706
-rw-r--r--doc/reference/meta-sections.txt17
-rw-r--r--src/Makefile.am3
-rw-r--r--src/compositor/meta-background-actor-private.h3
-rw-r--r--src/compositor/meta-background-actor.c59
-rw-r--r--src/compositor/meta-background-group-private.h11
-rw-r--r--src/compositor/meta-background-group.c59
-rw-r--r--src/compositor/meta-cullable.c191
-rw-r--r--src/compositor/meta-cullable.h68
-rw-r--r--src/compositor/meta-window-actor-private.h5
-rw-r--r--src/compositor/meta-window-actor.c35
-rw-r--r--src/compositor/meta-window-group.c113
-rw-r--r--src/compositor/meta-window-group.h26
12 files changed, 379 insertions, 211 deletions
diff --git a/doc/reference/meta-sections.txt b/doc/reference/meta-sections.txt
index 90f815249..7aa893177 100644
--- a/doc/reference/meta-sections.txt
+++ b/doc/reference/meta-sections.txt
@@ -389,6 +389,23 @@ meta_window_actor_get_type
</SECTION>
<SECTION>
+<FILE>meta-cullable</FILE>
+<TITLE>MetaCullable</TITLE>
+MetaCullable
+MetaCullableInterface
+meta_cullable_cull_out
+meta_cullable_reset_culling
+meta_cullable_cull_out_children
+meta_cullable_reset_culling_children
+<SUBSECTION Standard>
+META_TYPE_CULLABLE
+META_CULLABLE
+META_IS_CULLABLE
+META_CULLABLE_GET_IFACE
+meta_cullable_get_type
+</SECTION>
+
+<SECTION>
<FILE>prefs</FILE>
MetaPreference
MetaPrefsChangedFunc
diff --git a/src/Makefile.am b/src/Makefile.am
index 20bea802e..b81c6ec51 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -70,7 +70,8 @@ libmutter_wayland_la_SOURCES = \
compositor/meta-background-actor.c \
compositor/meta-background-actor-private.h \
compositor/meta-background-group.c \
- compositor/meta-background-group-private.h \
+ compositor/meta-cullable.c \
+ compositor/meta-cullable.h \
compositor/meta-module.c \
compositor/meta-module.h \
compositor/meta-plugin.c \
diff --git a/src/compositor/meta-background-actor-private.h b/src/compositor/meta-background-actor-private.h
index 9ab074ebd..d48fb03d4 100644
--- a/src/compositor/meta-background-actor-private.h
+++ b/src/compositor/meta-background-actor-private.h
@@ -6,9 +6,6 @@
#include <meta/screen.h>
#include <meta/meta-background-actor.h>
-void meta_background_actor_set_clip_region (MetaBackgroundActor *self,
- cairo_region_t *clip_region);
-
cairo_region_t *meta_background_actor_get_clip_region (MetaBackgroundActor *self);
#endif /* META_BACKGROUND_ACTOR_PRIVATE_H */
diff --git a/src/compositor/meta-background-actor.c b/src/compositor/meta-background-actor.c
index 32b6007b3..20744587a 100644
--- a/src/compositor/meta-background-actor.c
+++ b/src/compositor/meta-background-actor.c
@@ -41,20 +41,35 @@
#include <meta/errors.h>
#include <meta/meta-background.h>
#include "meta-background-actor-private.h"
+#include "meta-cullable.h"
struct _MetaBackgroundActorPrivate
{
cairo_region_t *clip_region;
};
-G_DEFINE_TYPE (MetaBackgroundActor, meta_background_actor, CLUTTER_TYPE_ACTOR);
+static void cullable_iface_init (MetaCullableInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (MetaBackgroundActor, meta_background_actor, CLUTTER_TYPE_ACTOR,
+ G_IMPLEMENT_INTERFACE (META_TYPE_CULLABLE, cullable_iface_init));
+
+static void
+set_clip_region (MetaBackgroundActor *self,
+ cairo_region_t *clip_region)
+{
+ MetaBackgroundActorPrivate *priv = self->priv;
+
+ g_clear_pointer (&priv->clip_region, (GDestroyNotify) cairo_region_destroy);
+ if (clip_region)
+ priv->clip_region = cairo_region_copy (clip_region);
+}
static void
meta_background_actor_dispose (GObject *object)
{
MetaBackgroundActor *self = META_BACKGROUND_ACTOR (object);
- meta_background_actor_set_clip_region (self, NULL);
+ set_clip_region (self, NULL);
G_OBJECT_CLASS (meta_background_actor_parent_class)->dispose (object);
}
@@ -166,31 +181,27 @@ meta_background_actor_new (void)
return CLUTTER_ACTOR (self);
}
-/**
- * meta_background_actor_set_clip_region:
- * @self: a #MetaBackgroundActor
- * @clip_region: (allow-none): the area of the actor (in allocate-relative
- * coordinates) that is visible.
- *
- * Sets the area of the background that is unobscured by overlapping windows.
- * This is used to optimize and only paint the visible portions.
- */
-void
-meta_background_actor_set_clip_region (MetaBackgroundActor *self,
- cairo_region_t *clip_region)
+static void
+meta_background_actor_cull_out (MetaCullable *cullable,
+ cairo_region_t *unobscured_region,
+ cairo_region_t *clip_region)
{
- MetaBackgroundActorPrivate *priv;
-
- g_return_if_fail (META_IS_BACKGROUND_ACTOR (self));
-
- priv = self->priv;
+ MetaBackgroundActor *self = META_BACKGROUND_ACTOR (cullable);
+ set_clip_region (self, clip_region);
+}
- g_clear_pointer (&priv->clip_region,
- (GDestroyNotify)
- cairo_region_destroy);
+static void
+meta_background_actor_reset_culling (MetaCullable *cullable)
+{
+ MetaBackgroundActor *self = META_BACKGROUND_ACTOR (cullable);
+ set_clip_region (self, NULL);
+}
- if (clip_region)
- priv->clip_region = cairo_region_copy (clip_region);
+static void
+cullable_iface_init (MetaCullableInterface *iface)
+{
+ iface->cull_out = meta_background_actor_cull_out;
+ iface->reset_culling = meta_background_actor_reset_culling;
}
/**
diff --git a/src/compositor/meta-background-group-private.h b/src/compositor/meta-background-group-private.h
deleted file mode 100644
index 1ee7a6737..000000000
--- a/src/compositor/meta-background-group-private.h
+++ /dev/null
@@ -1,11 +0,0 @@
-/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
-
-#ifndef META_BACKGROUND_GROUP_PRIVATE_H
-#define META_BACKGROUND_GROUP_PRIVATE_H
-
-#include <meta/screen.h>
-#include <meta/meta-background-group.h>
-
-void meta_background_group_set_clip_region (MetaBackgroundGroup *self,
- cairo_region_t *visible_region);
-#endif /* META_BACKGROUND_GROUP_PRIVATE_H */
diff --git a/src/compositor/meta-background-group.c b/src/compositor/meta-background-group.c
index 092dd1889..2ff01d3d9 100644
--- a/src/compositor/meta-background-group.c
+++ b/src/compositor/meta-background-group.c
@@ -16,12 +16,13 @@
#include <config.h>
-#include "compositor-private.h"
-#include "clutter-utils.h"
-#include "meta-background-actor-private.h"
-#include "meta-background-group-private.h"
+#include <meta/meta-background-group.h>
+#include "meta-cullable.h"
-G_DEFINE_TYPE (MetaBackgroundGroup, meta_background_group, CLUTTER_TYPE_ACTOR);
+static void cullable_iface_init (MetaCullableInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (MetaBackgroundGroup, meta_background_group, CLUTTER_TYPE_ACTOR,
+ G_IMPLEMENT_INTERFACE (META_TYPE_CULLABLE, cullable_iface_init));
static void
meta_background_group_class_init (MetaBackgroundGroupClass *klass)
@@ -29,43 +30,29 @@ meta_background_group_class_init (MetaBackgroundGroupClass *klass)
}
static void
-meta_background_group_init (MetaBackgroundGroup *self)
+meta_background_group_cull_out (MetaCullable *cullable,
+ cairo_region_t *unobscured_region,
+ cairo_region_t *clip_region)
{
+ meta_cullable_cull_out_children (cullable, unobscured_region, clip_region);
}
-/**
- * meta_background_group_set_clip_region:
- * @self: a #MetaBackgroundGroup
- * @region: (allow-none): the parts of the background to paint
- *
- * Sets the area of the backgrounds that is unobscured by overlapping windows.
- * This is used to optimize and only paint the visible portions.
- */
-void
-meta_background_group_set_clip_region (MetaBackgroundGroup *self,
- cairo_region_t *region)
+static void
+meta_background_group_reset_culling (MetaCullable *cullable)
{
- ClutterActor *child;
- for (child = clutter_actor_get_first_child (CLUTTER_ACTOR (self));
- child != NULL;
- child = clutter_actor_get_next_sibling (child))
- {
- if (META_IS_BACKGROUND_ACTOR (child))
- {
- meta_background_actor_set_clip_region (META_BACKGROUND_ACTOR (child), region);
- }
- else if (META_IS_BACKGROUND_GROUP (child))
- {
- int x, y;
+ meta_cullable_reset_culling_children (cullable);
+}
- if (!meta_actor_is_untransformed (child, &x, &y))
- continue;
+static void
+cullable_iface_init (MetaCullableInterface *iface)
+{
+ iface->cull_out = meta_background_group_cull_out;
+ iface->reset_culling = meta_background_group_reset_culling;
+}
- cairo_region_translate (region, -x, -y);
- meta_background_group_set_clip_region (META_BACKGROUND_GROUP (child), region);
- cairo_region_translate (region, x, y);
- }
- }
+static void
+meta_background_group_init (MetaBackgroundGroup *self)
+{
}
ClutterActor *
diff --git a/src/compositor/meta-cullable.c b/src/compositor/meta-cullable.c
new file mode 100644
index 000000000..a139166b5
--- /dev/null
+++ b/src/compositor/meta-cullable.c
@@ -0,0 +1,191 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/*
+ * Copyright (C) 2013 Red Hat
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Written by:
+ * Owen Taylor <otaylor@redhat.com>
+ * Ray Strode <rstrode@redhat.com>
+ * Jasper St. Pierre <jstpierre@mecheye.net>
+ */
+
+#include "config.h"
+#include "meta-cullable.h"
+#include "clutter-utils.h"
+
+G_DEFINE_INTERFACE (MetaCullable, meta_cullable, CLUTTER_TYPE_ACTOR);
+
+/**
+ * SECTION:meta-cullable
+ * @title: MetaCullable
+ * @short_description: CPU culling operations for efficient drawing
+ *
+ * When we are painting a stack of 5-10 large actors, the standard
+ * bottom-to-top method of drawing every actor results in a tremendous
+ * amount of overdraw. If these actors are painting textures like
+ * windows, it can easily max out the available memory bandwidth on a
+ * low-end graphics chipset. It's even worse if window textures are
+ * being accessed over the AGP bus.
+ *
+ * #MetaCullable is our solution. The basic technique applied here is to
+ * do a pre-pass before painting where we walk each actor from top to bottom
+ * and ask each actor to "cull itself out". We pass in a region it can copy
+ * to clip its drawing to, and the actor can subtract its fully opaque pixels
+ * so that actors underneath know not to draw there as well.
+ */
+
+/**
+ * meta_cullable_cull_out_children:
+ * @cullable: The #MetaCullable
+ * @unobscured_region: The unobscured region, as passed into cull_out()
+ * @clip_region: The clip region, as passed into cull_out()
+ *
+ * This is a helper method for actors that want to recurse over their
+ * child actors, and cull them out.
+ *
+ * See #MetaCullable and meta_cullable_cull_out() for more details.
+ */
+void
+meta_cullable_cull_out_children (MetaCullable *cullable,
+ cairo_region_t *unobscured_region,
+ cairo_region_t *clip_region)
+{
+ ClutterActor *actor = CLUTTER_ACTOR (cullable);
+ ClutterActor *child;
+ ClutterActorIter iter;
+
+ clutter_actor_iter_init (&iter, actor);
+ while (clutter_actor_iter_prev (&iter, &child))
+ {
+ int x, y;
+
+ if (!CLUTTER_ACTOR_IS_VISIBLE (child))
+ continue;
+
+ /* If an actor has effects applied, then that can change the area
+ * it paints and the opacity, so we no longer can figure out what
+ * portion of the actor is obscured and what portion of the screen
+ * it obscures, so we skip the actor.
+ *
+ * This has a secondary beneficial effect: if a ClutterOffscreenEffect
+ * is applied to an actor, then our clipped redraws interfere with the
+ * caching of the FBO - even if we only need to draw a small portion
+ * of the window right now, ClutterOffscreenEffect may use other portions
+ * of the FBO later. So, skipping actors with effects applied also
+ * prevents these bugs.
+ *
+ * Theoretically, we should check clutter_actor_get_offscreen_redirect()
+ * as well for the same reason, but omitted for simplicity in the
+ * hopes that no-one will do that.
+ */
+ if (clutter_actor_has_effects (child))
+ continue;
+
+ if (!META_IS_CULLABLE (child))
+ continue;
+
+ if (!meta_actor_is_untransformed (child, &x, &y))
+ continue;
+
+ /* Temporarily move to the coordinate system of the actor */
+ cairo_region_translate (unobscured_region, - x, - y);
+ cairo_region_translate (clip_region, - x, - y);
+
+ meta_cullable_cull_out (META_CULLABLE (child), unobscured_region, clip_region);
+
+ cairo_region_translate (unobscured_region, x, y);
+ cairo_region_translate (clip_region, x, y);
+ }
+}
+
+/**
+ * meta_cullable_reset_culling_children:
+ * @cullable: The #MetaCullable
+ *
+ * This is a helper method for actors that want to recurse over their
+ * child actors, and cull them out.
+ *
+ * See #MetaCullable and meta_cullable_reset_culling() for more details.
+ */
+void
+meta_cullable_reset_culling_children (MetaCullable *cullable)
+{
+ ClutterActor *actor = CLUTTER_ACTOR (cullable);
+ ClutterActor *child;
+ ClutterActorIter iter;
+
+ clutter_actor_iter_init (&iter, actor);
+ while (clutter_actor_iter_next (&iter, &child))
+ {
+ if (!META_IS_CULLABLE (child))
+ continue;
+
+ meta_cullable_reset_culling (META_CULLABLE (child));
+ }
+}
+
+static void
+meta_cullable_default_init (MetaCullableInterface *iface)
+{
+}
+
+/**
+ * meta_cullable_cull_out:
+ * @cullable: The #MetaCullable
+ * @unobscured_region: The unobscured region, in @cullable's space.
+ * @clip_region: The clip region, in @cullable's space.
+ *
+ * When #MetaWindowGroup is painted, we walk over its direct cullable
+ * children from top to bottom and ask themselves to "cull out". Cullables
+ * can use @unobscured_region and @clip_region to clip their drawing. Actors
+ * interested in eliminating overdraw should copy the @clip_region and only
+ * paint those parts, as everything else has been obscured by actors above it.
+ *
+ * Actors that may have fully opaque parts should also subtract out a region
+ * that is fully opaque from @unobscured_region and @clip_region.
+ *
+ * @unobscured_region and @clip_region are extremely similar. The difference
+ * is that @clip_region starts off with the stage's clip, if Clutter detects
+ * that we're doing a clipped redraw. @unobscured_region, however, starts off
+ * with the full stage size, so actors that may want to record what parts of
+ * their window are unobscured for e.g. scheduling repaints can do so.
+ *
+ * Actors that have children can also use the meta_cullable_cull_out_children()
+ * helper method to do a simple cull across all their children.
+ */
+void
+meta_cullable_cull_out (MetaCullable *cullable,
+ cairo_region_t *unobscured_region,
+ cairo_region_t *clip_region)
+{
+ META_CULLABLE_GET_IFACE (cullable)->cull_out (cullable, unobscured_region, clip_region);
+}
+
+/**
+ * meta_cullable_reset_culling:
+ * @cullable: The #MetaCullable
+ *
+ * Actors that copied data in their cull_out() implementation can now
+ * reset their data, as the paint is now over. Additional paints may be
+ * done by #ClutterClone or similar, and they should not be affected by
+ * the culling operation.
+ */
+void
+meta_cullable_reset_culling (MetaCullable *cullable)
+{
+ META_CULLABLE_GET_IFACE (cullable)->reset_culling (cullable);
+}
diff --git a/src/compositor/meta-cullable.h b/src/compositor/meta-cullable.h
new file mode 100644
index 000000000..5a8c215f1
--- /dev/null
+++ b/src/compositor/meta-cullable.h
@@ -0,0 +1,68 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+
+/*
+ * Copyright (C) 2013 Red Hat
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Written by:
+ * Owen Taylor <otaylor@redhat.com>
+ * Ray Strode <rstrode@redhat.com>
+ * Jasper St. Pierre <jstpierre@mecheye.net>
+ */
+
+#ifndef __META_CULLABLE_H__
+#define __META_CULLABLE_H__
+
+#include <clutter/clutter.h>
+
+G_BEGIN_DECLS
+
+#define META_TYPE_CULLABLE (meta_cullable_get_type ())
+#define META_CULLABLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_CULLABLE, MetaCullable))
+#define META_IS_CULLABLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_CULLABLE))
+#define META_CULLABLE_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), META_TYPE_CULLABLE, MetaCullableInterface))
+
+typedef struct _MetaCullable MetaCullable;
+typedef struct _MetaCullableInterface MetaCullableInterface;
+
+struct _MetaCullableInterface
+{
+ GTypeInterface g_iface;
+
+ void (* cull_out) (MetaCullable *cullable,
+ cairo_region_t *unobscured_region,
+ cairo_region_t *clip_region);
+ void (* reset_culling) (MetaCullable *cullable);
+};
+
+GType meta_cullable_get_type (void);
+
+void meta_cullable_cull_out (MetaCullable *cullable,
+ cairo_region_t *unobscured_region,
+ cairo_region_t *clip_region);
+void meta_cullable_reset_culling (MetaCullable *cullable);
+
+/* Utility methods for implementations */
+void meta_cullable_cull_out_children (MetaCullable *cullable,
+ cairo_region_t *unobscured_region,
+ cairo_region_t *clip_region);
+void meta_cullable_reset_culling_children (MetaCullable *cullable);
+
+G_END_DECLS
+
+#endif /* __META_CULLABLE_H__ */
+
diff --git a/src/compositor/meta-window-actor-private.h b/src/compositor/meta-window-actor-private.h
index 2b9cb4138..e37d8e81e 100644
--- a/src/compositor/meta-window-actor-private.h
+++ b/src/compositor/meta-window-actor-private.h
@@ -67,11 +67,6 @@ void meta_window_actor_set_updates_frozen (MetaWindowActor *self,
void meta_window_actor_queue_frame_drawn (MetaWindowActor *self,
gboolean no_delay_frame);
-void meta_window_actor_cull_out (MetaWindowActor *self,
- cairo_region_t *unobscured_region,
- cairo_region_t *clip_region);
-void meta_window_actor_reset_culling (MetaWindowActor *self);
-
void meta_window_actor_set_unobscured_region (MetaWindowActor *self,
cairo_region_t *unobscured_region);
diff --git a/src/compositor/meta-window-actor.c b/src/compositor/meta-window-actor.c
index 1bbb2255f..bc4fc9cb5 100644
--- a/src/compositor/meta-window-actor.c
+++ b/src/compositor/meta-window-actor.c
@@ -35,6 +35,7 @@
#include "region-utils.h"
#include "meta-wayland-private.h"
#include "monitor-private.h"
+#include "meta-cullable.h"
enum {
POSITION_CHANGED,
@@ -202,7 +203,10 @@ static void do_send_frame_timings (MetaWindowActor *self,
gint refresh_interval,
gint64 presentation_time);
-G_DEFINE_TYPE (MetaWindowActor, meta_window_actor, CLUTTER_TYPE_ACTOR);
+static void cullable_iface_init (MetaCullableInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (MetaWindowActor, meta_window_actor, CLUTTER_TYPE_ACTOR,
+ G_IMPLEMENT_INTERFACE (META_TYPE_CULLABLE, cullable_iface_init));
static void
frame_data_free (FrameData *frame)
@@ -1951,11 +1955,13 @@ meta_window_actor_set_clip_region_beneath (MetaWindowActor *self,
}
}
-void
-meta_window_actor_cull_out (MetaWindowActor *self,
- cairo_region_t *unobscured_region,
- cairo_region_t *clip_region)
+static void
+meta_window_actor_cull_out (MetaCullable *cullable,
+ cairo_region_t *unobscured_region,
+ cairo_region_t *clip_region)
{
+ MetaWindowActor *self = META_WINDOW_ACTOR (cullable);
+
if (!meta_is_wayland_compositor ())
{
MetaCompScreen *info = meta_screen_get_compositor_data (self->priv->screen);
@@ -1981,22 +1987,23 @@ meta_window_actor_cull_out (MetaWindowActor *self,
meta_window_actor_set_clip_region_beneath (self, clip_region);
}
-/**
- * meta_window_actor_reset_culling:
- * @self: a #MetaWindowActor
- *
- * Unsets the regions set by meta_window_actor_set_clip_region() and
- * meta_window_actor_set_clip_region_beneath()
- */
-void
-meta_window_actor_reset_culling (MetaWindowActor *self)
+static void
+meta_window_actor_reset_culling (MetaCullable *cullable)
{
+ MetaWindowActor *self = META_WINDOW_ACTOR (cullable);
MetaWindowActorPrivate *priv = self->priv;
meta_surface_actor_set_clip_region (priv->surface, NULL);
g_clear_pointer (&priv->shadow_clip, cairo_region_destroy);
}
+static void
+cullable_iface_init (MetaCullableInterface *iface)
+{
+ iface->cull_out = meta_window_actor_cull_out;
+ iface->reset_culling = meta_window_actor_reset_culling;
+}
+
/* When running as a wayland compositor we don't make requests for
* replacement pixmaps when resizing windows, we will instead be
* asked to attach replacement buffers by the clients. */
diff --git a/src/compositor/meta-window-group.c b/src/compositor/meta-window-group.c
index be1b54462..f76b2e0a5 100644
--- a/src/compositor/meta-window-group.c
+++ b/src/compositor/meta-window-group.c
@@ -11,9 +11,8 @@
#include "compositor-private.h"
#include "meta-window-actor-private.h"
#include "meta-window-group.h"
-#include "meta-background-actor-private.h"
-#include "meta-background-group-private.h"
#include "window-private.h"
+#include "meta-cullable.h"
struct _MetaWindowGroupClass
{
@@ -27,7 +26,10 @@ struct _MetaWindowGroup
MetaScreen *screen;
};
-G_DEFINE_TYPE (MetaWindowGroup, meta_window_group, CLUTTER_TYPE_ACTOR);
+static void cullable_iface_init (MetaCullableInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (MetaWindowGroup, meta_window_group, CLUTTER_TYPE_ACTOR,
+ G_IMPLEMENT_INTERFACE (META_TYPE_CULLABLE, cullable_iface_init));
/* Help macros to scale from OpenGL <-1,1> coordinates system to
* window coordinates ranging [0,window-size]. Borrowed from clutter-utils.c
@@ -88,101 +90,24 @@ painting_untransformed (MetaWindowGroup *window_group,
}
static void
-meta_window_group_cull_out (MetaWindowGroup *group,
- cairo_region_t *unobscured_region,
- cairo_region_t *clip_region)
+meta_window_group_cull_out (MetaCullable *cullable,
+ cairo_region_t *unobscured_region,
+ cairo_region_t *clip_region)
{
- ClutterActor *actor = CLUTTER_ACTOR (group);
- ClutterActor *child;
-
- /* We walk the list from top to bottom (opposite of painting order),
- * and subtract the opaque area of each window out of the visible
- * region that we pass to the windows below.
- */
- clutter_actor_iter_init (&iter, actor);
- while (clutter_actor_iter_prev (&iter, &child))
- {
- if (!CLUTTER_ACTOR_IS_VISIBLE (child))
- continue;
-
- /* If an actor has effects applied, then that can change the area
- * it paints and the opacity, so we no longer can figure out what
- * portion of the actor is obscured and what portion of the screen
- * it obscures, so we skip the actor.
- *
- * This has a secondary beneficial effect: if a ClutterOffscreenEffect
- * is applied to an actor, then our clipped redraws interfere with the
- * caching of the FBO - even if we only need to draw a small portion
- * of the window right now, ClutterOffscreenEffect may use other portions
- * of the FBO later. So, skipping actors with effects applied also
- * prevents these bugs.
- *
- * Theoretically, we should check clutter_actor_get_offscreen_redirect()
- * as well for the same reason, but omitted for simplicity in the
- * hopes that no-one will do that.
- */
- if (clutter_actor_has_effects (child))
- continue;
-
- if (META_IS_WINDOW_ACTOR (child))
- {
- int x, y;
-
- if (!meta_actor_is_untransformed (child, &x, &y))
- continue;
-
- /* Temporarily move to the coordinate system of the actor */
- cairo_region_translate (unobscured_region, - x, - y);
- cairo_region_translate (clip_region, - x, - y);
-
- meta_window_actor_cull_out (META_WINDOW_ACTOR (child), unobscured_region, clip_region);
-
- cairo_region_translate (unobscured_region, x, y);
- cairo_region_translate (clip_region, x, y);
- }
- else if (META_IS_BACKGROUND_ACTOR (child) ||
- META_IS_BACKGROUND_GROUP (child))
- {
- int x, y;
-
- if (!meta_actor_is_untransformed (child, &x, &y))
- continue;
-
- cairo_region_translate (clip_region, - x, - y);
-
- if (META_IS_BACKGROUND_GROUP (child))
- meta_background_group_set_clip_region (META_BACKGROUND_GROUP (child), clip_region);
- else
- meta_background_actor_set_clip_region (META_BACKGROUND_ACTOR (child), clip_region);
- cairo_region_translate (clip_region, x, y);
- }
- }
+ meta_cullable_cull_out_children (cullable, unobscured_region, clip_region);
}
static void
-meta_window_group_reset_culling (MetaWindowGroup *group)
+meta_window_group_reset_culling (MetaCullable *cullable)
{
- ClutterActor *actor = CLUTTER_ACTOR (group);
- ClutterActor *child;
- ClutterActorIter iter;
+ meta_cullable_reset_culling_children (cullable);
+}
- /* Now that we are done painting, unset the visible regions (they will
- * mess up painting clones of our actors)
- */
- clutter_actor_iter_init (&iter, actor);
- while (clutter_actor_iter_next (&iter, &child))
- {
- if (META_IS_WINDOW_ACTOR (child))
- {
- MetaWindowActor *window_actor = META_WINDOW_ACTOR (child);
- meta_window_actor_reset_culling (window_actor);
- }
- else if (META_IS_BACKGROUND_ACTOR (child))
- {
- MetaBackgroundActor *background_actor = META_BACKGROUND_ACTOR (child);
- meta_background_actor_set_clip_region (background_actor, NULL);
- }
- }
+static void
+cullable_iface_init (MetaCullableInterface *iface)
+{
+ iface->cull_out = meta_window_group_cull_out;
+ iface->reset_culling = meta_window_group_reset_culling;
}
static void
@@ -267,14 +192,14 @@ meta_window_group_paint (ClutterActor *actor)
}
}
- meta_window_group_cull_out (window_group, unobscured_region, clip_region);
+ meta_cullable_cull_out (META_CULLABLE (window_group), unobscured_region, clip_region);
cairo_region_destroy (unobscured_region);
cairo_region_destroy (clip_region);
CLUTTER_ACTOR_CLASS (meta_window_group_parent_class)->paint (actor);
- meta_window_group_reset_culling (window_group);
+ meta_cullable_reset_culling (META_CULLABLE (window_group));
}
static gboolean
diff --git a/src/compositor/meta-window-group.h b/src/compositor/meta-window-group.h
index 1c3eebf5c..d624ac68c 100644
--- a/src/compositor/meta-window-group.h
+++ b/src/compositor/meta-window-group.h
@@ -11,29 +11,9 @@
* MetaWindowGroup:
*
* This class is a subclass of ClutterActor with special handling for
- * MetaWindowActor/MetaBackgroundActor/MetaBackgroundGroup when painting
- * children.
- *
- * When we are painting a stack of 5-10 maximized windows, the
- * standard bottom-to-top method of drawing every actor results in a
- * tremendous amount of overdraw and can easily max out the available
- * memory bandwidth on a low-end graphics chipset. It's even worse if
- * window textures are being accessed over the AGP bus.
- *
- * The basic technique applied here is to do a pre-pass before painting
- * where we walk window from top to bottom and compute the visible area
- * at each step by subtracting out the windows above it. The visible
- * area is passed to MetaWindowActor which uses it to clip the portion of
- * the window which drawn and avoid redrawing the shadow if it is completely
- * obscured.
- *
- * A caveat is that this is ineffective if applications are using ARGB
- * visuals, since we have no way of knowing whether a window obscures
- * the windows behind it or not. Alternate approaches using the depth
- * or stencil buffer rather than client side regions might be able to
- * handle alpha windows, but the combination of glAlphaFunc and stenciling
- * tends not to be efficient except on newer cards. (And on newer cards
- * we have lots of memory and bandwidth.)
+ * #MetaCullable when painting children. It uses code similar to
+ * meta_cullable_cull_out_children(), but also has additional special
+ * cases for the undirected window, and similar.
*/
#define META_TYPE_WINDOW_GROUP (meta_window_group_get_type ())