mirror of
https://github.com/brl/mutter.git
synced 2024-11-27 18:40:40 -05:00
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
This commit is contained in:
parent
d8c66077f0
commit
47144253e4
@ -388,6 +388,23 @@ MetaWindowActorPrivate
|
|||||||
meta_window_actor_get_type
|
meta_window_actor_get_type
|
||||||
</SECTION>
|
</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>
|
<SECTION>
|
||||||
<FILE>prefs</FILE>
|
<FILE>prefs</FILE>
|
||||||
MetaPreference
|
MetaPreference
|
||||||
|
@ -55,7 +55,8 @@ libmutter_la_SOURCES = \
|
|||||||
compositor/meta-background-actor.c \
|
compositor/meta-background-actor.c \
|
||||||
compositor/meta-background-actor-private.h \
|
compositor/meta-background-actor-private.h \
|
||||||
compositor/meta-background-group.c \
|
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.c \
|
||||||
compositor/meta-module.h \
|
compositor/meta-module.h \
|
||||||
compositor/meta-plugin.c \
|
compositor/meta-plugin.c \
|
||||||
|
@ -6,9 +6,6 @@
|
|||||||
#include <meta/screen.h>
|
#include <meta/screen.h>
|
||||||
#include <meta/meta-background-actor.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);
|
cairo_region_t *meta_background_actor_get_clip_region (MetaBackgroundActor *self);
|
||||||
|
|
||||||
#endif /* META_BACKGROUND_ACTOR_PRIVATE_H */
|
#endif /* META_BACKGROUND_ACTOR_PRIVATE_H */
|
||||||
|
@ -41,20 +41,35 @@
|
|||||||
#include <meta/errors.h>
|
#include <meta/errors.h>
|
||||||
#include <meta/meta-background.h>
|
#include <meta/meta-background.h>
|
||||||
#include "meta-background-actor-private.h"
|
#include "meta-background-actor-private.h"
|
||||||
|
#include "meta-cullable.h"
|
||||||
|
|
||||||
struct _MetaBackgroundActorPrivate
|
struct _MetaBackgroundActorPrivate
|
||||||
{
|
{
|
||||||
cairo_region_t *clip_region;
|
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
|
static void
|
||||||
meta_background_actor_dispose (GObject *object)
|
meta_background_actor_dispose (GObject *object)
|
||||||
{
|
{
|
||||||
MetaBackgroundActor *self = META_BACKGROUND_ACTOR (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);
|
G_OBJECT_CLASS (meta_background_actor_parent_class)->dispose (object);
|
||||||
}
|
}
|
||||||
@ -166,31 +181,27 @@ meta_background_actor_new (void)
|
|||||||
return CLUTTER_ACTOR (self);
|
return CLUTTER_ACTOR (self);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
static void
|
||||||
* meta_background_actor_set_clip_region:
|
meta_background_actor_cull_out (MetaCullable *cullable,
|
||||||
* @self: a #MetaBackgroundActor
|
cairo_region_t *unobscured_region,
|
||||||
* @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)
|
cairo_region_t *clip_region)
|
||||||
{
|
{
|
||||||
MetaBackgroundActorPrivate *priv;
|
MetaBackgroundActor *self = META_BACKGROUND_ACTOR (cullable);
|
||||||
|
set_clip_region (self, clip_region);
|
||||||
|
}
|
||||||
|
|
||||||
g_return_if_fail (META_IS_BACKGROUND_ACTOR (self));
|
static void
|
||||||
|
meta_background_actor_reset_culling (MetaCullable *cullable)
|
||||||
|
{
|
||||||
|
MetaBackgroundActor *self = META_BACKGROUND_ACTOR (cullable);
|
||||||
|
set_clip_region (self, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
priv = self->priv;
|
static void
|
||||||
|
cullable_iface_init (MetaCullableInterface *iface)
|
||||||
g_clear_pointer (&priv->clip_region,
|
{
|
||||||
(GDestroyNotify)
|
iface->cull_out = meta_background_actor_cull_out;
|
||||||
cairo_region_destroy);
|
iface->reset_culling = meta_background_actor_reset_culling;
|
||||||
|
|
||||||
if (clip_region)
|
|
||||||
priv->clip_region = cairo_region_copy (clip_region);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -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 */
|
|
@ -16,12 +16,13 @@
|
|||||||
|
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
|
|
||||||
#include "compositor-private.h"
|
#include <meta/meta-background-group.h>
|
||||||
#include "clutter-utils.h"
|
#include "meta-cullable.h"
|
||||||
#include "meta-background-actor-private.h"
|
|
||||||
#include "meta-background-group-private.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
|
static void
|
||||||
meta_background_group_class_init (MetaBackgroundGroupClass *klass)
|
meta_background_group_class_init (MetaBackgroundGroupClass *klass)
|
||||||
@ -29,43 +30,29 @@ meta_background_group_class_init (MetaBackgroundGroupClass *klass)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
static void
|
||||||
* meta_background_group_set_clip_region:
|
meta_background_group_reset_culling (MetaCullable *cullable)
|
||||||
* @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)
|
|
||||||
{
|
{
|
||||||
ClutterActor *child;
|
meta_cullable_reset_culling_children (cullable);
|
||||||
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;
|
|
||||||
|
|
||||||
if (!meta_actor_is_untransformed (child, &x, &y))
|
static void
|
||||||
continue;
|
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);
|
static void
|
||||||
meta_background_group_set_clip_region (META_BACKGROUND_GROUP (child), region);
|
meta_background_group_init (MetaBackgroundGroup *self)
|
||||||
cairo_region_translate (region, x, y);
|
{
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ClutterActor *
|
ClutterActor *
|
||||||
|
191
src/compositor/meta-cullable.c
Normal file
191
src/compositor/meta-cullable.c
Normal file
@ -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);
|
||||||
|
}
|
68
src/compositor/meta-cullable.h
Normal file
68
src/compositor/meta-cullable.h
Normal file
@ -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__ */
|
||||||
|
|
@ -55,11 +55,6 @@ void meta_window_actor_set_updates_frozen (MetaWindowActor *self,
|
|||||||
void meta_window_actor_queue_frame_drawn (MetaWindowActor *self,
|
void meta_window_actor_queue_frame_drawn (MetaWindowActor *self,
|
||||||
gboolean no_delay_frame);
|
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,
|
void meta_window_actor_set_unobscured_region (MetaWindowActor *self,
|
||||||
cairo_region_t *unobscured_region);
|
cairo_region_t *unobscured_region);
|
||||||
|
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
#include "meta-texture-rectangle.h"
|
#include "meta-texture-rectangle.h"
|
||||||
#include "region-utils.h"
|
#include "region-utils.h"
|
||||||
#include "monitor-private.h"
|
#include "monitor-private.h"
|
||||||
|
#include "meta-cullable.h"
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
POSITION_CHANGED,
|
POSITION_CHANGED,
|
||||||
@ -191,7 +192,10 @@ static void do_send_frame_timings (MetaWindowActor *self,
|
|||||||
gint refresh_interval,
|
gint refresh_interval,
|
||||||
gint64 presentation_time);
|
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
|
static void
|
||||||
frame_data_free (FrameData *frame)
|
frame_data_free (FrameData *frame)
|
||||||
@ -1848,11 +1852,12 @@ meta_window_actor_set_clip_region_beneath (MetaWindowActor *self,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
static void
|
||||||
meta_window_actor_cull_out (MetaWindowActor *self,
|
meta_window_actor_cull_out (MetaCullable *cullable,
|
||||||
cairo_region_t *unobscured_region,
|
cairo_region_t *unobscured_region,
|
||||||
cairo_region_t *clip_region)
|
cairo_region_t *clip_region)
|
||||||
{
|
{
|
||||||
|
MetaWindowActor *self = META_WINDOW_ACTOR (cullable);
|
||||||
MetaCompScreen *info = meta_screen_get_compositor_data (self->priv->screen);
|
MetaCompScreen *info = meta_screen_get_compositor_data (self->priv->screen);
|
||||||
|
|
||||||
/* Don't do any culling for the unredirected window */
|
/* Don't do any culling for the unredirected window */
|
||||||
@ -1875,16 +1880,10 @@ meta_window_actor_cull_out (MetaWindowActor *self,
|
|||||||
meta_window_actor_set_clip_region_beneath (self, clip_region);
|
meta_window_actor_set_clip_region_beneath (self, clip_region);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
static void
|
||||||
* meta_window_actor_reset_culling:
|
meta_window_actor_reset_culling (MetaCullable *cullable)
|
||||||
* @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)
|
|
||||||
{
|
{
|
||||||
|
MetaWindowActor *self = META_WINDOW_ACTOR (cullable);
|
||||||
MetaWindowActorPrivate *priv = self->priv;
|
MetaWindowActorPrivate *priv = self->priv;
|
||||||
|
|
||||||
meta_shaped_texture_set_clip_region (META_SHAPED_TEXTURE (priv->actor),
|
meta_shaped_texture_set_clip_region (META_SHAPED_TEXTURE (priv->actor),
|
||||||
@ -1892,6 +1891,13 @@ meta_window_actor_reset_culling (MetaWindowActor *self)
|
|||||||
g_clear_pointer (&priv->shadow_clip, cairo_region_destroy);
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
check_needs_pixmap (MetaWindowActor *self)
|
check_needs_pixmap (MetaWindowActor *self)
|
||||||
{
|
{
|
||||||
|
@ -11,8 +11,8 @@
|
|||||||
#include "compositor-private.h"
|
#include "compositor-private.h"
|
||||||
#include "meta-window-actor-private.h"
|
#include "meta-window-actor-private.h"
|
||||||
#include "meta-window-group.h"
|
#include "meta-window-group.h"
|
||||||
#include "meta-background-actor-private.h"
|
#include "window-private.h"
|
||||||
#include "meta-background-group-private.h"
|
#include "meta-cullable.h"
|
||||||
|
|
||||||
struct _MetaWindowGroupClass
|
struct _MetaWindowGroupClass
|
||||||
{
|
{
|
||||||
@ -26,7 +26,10 @@ struct _MetaWindowGroup
|
|||||||
MetaScreen *screen;
|
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
|
/* Help macros to scale from OpenGL <-1,1> coordinates system to
|
||||||
* window coordinates ranging [0,window-size]. Borrowed from clutter-utils.c
|
* window coordinates ranging [0,window-size]. Borrowed from clutter-utils.c
|
||||||
@ -87,103 +90,24 @@ painting_untransformed (MetaWindowGroup *window_group,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
meta_window_group_cull_out (MetaWindowGroup *group,
|
meta_window_group_cull_out (MetaCullable *cullable,
|
||||||
cairo_region_t *unobscured_region,
|
cairo_region_t *unobscured_region,
|
||||||
cairo_region_t *clip_region)
|
cairo_region_t *clip_region)
|
||||||
{
|
{
|
||||||
ClutterActor *actor = CLUTTER_ACTOR (group);
|
meta_cullable_cull_out_children (cullable, unobscured_region, clip_region);
|
||||||
ClutterActor *child;
|
|
||||||
ClutterActorIter iter;
|
|
||||||
|
|
||||||
/* 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
meta_window_group_reset_culling (MetaWindowGroup *group)
|
meta_window_group_reset_culling (MetaCullable *cullable)
|
||||||
{
|
{
|
||||||
ClutterActor *actor = CLUTTER_ACTOR (group);
|
meta_cullable_reset_culling_children (cullable);
|
||||||
ClutterActor *child;
|
}
|
||||||
ClutterActorIter iter;
|
|
||||||
|
|
||||||
/* Now that we are done painting, unset the visible regions (they will
|
static void
|
||||||
* mess up painting clones of our actors)
|
cullable_iface_init (MetaCullableInterface *iface)
|
||||||
*/
|
{
|
||||||
clutter_actor_iter_init (&iter, actor);
|
iface->cull_out = meta_window_group_cull_out;
|
||||||
while (clutter_actor_iter_next (&iter, &child))
|
iface->reset_culling = meta_window_group_reset_culling;
|
||||||
{
|
|
||||||
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
|
static void
|
||||||
@ -265,14 +189,14 @@ meta_window_group_paint (ClutterActor *actor)
|
|||||||
cairo_region_subtract_rectangle (clip_region, &unredirected_rect);
|
cairo_region_subtract_rectangle (clip_region, &unredirected_rect);
|
||||||
}
|
}
|
||||||
|
|
||||||
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 (unobscured_region);
|
||||||
cairo_region_destroy (clip_region);
|
cairo_region_destroy (clip_region);
|
||||||
|
|
||||||
CLUTTER_ACTOR_CLASS (meta_window_group_parent_class)->paint (actor);
|
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
|
static gboolean
|
||||||
|
@ -11,29 +11,9 @@
|
|||||||
* MetaWindowGroup:
|
* MetaWindowGroup:
|
||||||
*
|
*
|
||||||
* This class is a subclass of ClutterActor with special handling for
|
* This class is a subclass of ClutterActor with special handling for
|
||||||
* MetaWindowActor/MetaBackgroundActor/MetaBackgroundGroup when painting
|
* #MetaCullable when painting children. It uses code similar to
|
||||||
* children.
|
* meta_cullable_cull_out_children(), but also has additional special
|
||||||
*
|
* cases for the undirected window, and similar.
|
||||||
* 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.)
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define META_TYPE_WINDOW_GROUP (meta_window_group_get_type ())
|
#define META_TYPE_WINDOW_GROUP (meta_window_group_get_type ())
|
||||||
|
Loading…
Reference in New Issue
Block a user