[mutter/wip/gcampax/background: 2/8] Reintroduce background crossfading
- From: Giovanni Campagna <gcampagna src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [mutter/wip/gcampax/background: 2/8] Reintroduce background crossfading
- Date: Mon, 4 Feb 2013 23:12:16 +0000 (UTC)
commit 9759760618f2d20e065104847f0f43b9dbf687c5
Author: Giovanni Campagna <gcampagna src gnome org>
Date: Sun Nov 11 00:16:48 2012 +0100
Reintroduce background crossfading
... but do it right, using Clutter animation framework for vblank syncing
and Cogl to generate GLSL shaders that do the hard work of blending the
old and the new background in HW.
https://bugzilla.gnome.org/show_bug.cgi?id=682427
src/compositor/cogl-utils.c | 116 ++++++++--------
src/compositor/cogl-utils.h | 10 +-
src/compositor/compositor.c | 15 --
src/compositor/meta-background-actor.c | 236 +++++++++++++++++++++++++-------
4 files changed, 247 insertions(+), 130 deletions(-)
---
diff --git a/src/compositor/cogl-utils.c b/src/compositor/cogl-utils.c
index 5dbe3df..509d2d0 100644
--- a/src/compositor/cogl-utils.c
+++ b/src/compositor/cogl-utils.c
@@ -23,47 +23,8 @@
#include "cogl-utils.h"
-/**
- * meta_create_color_texture_4ub:
- * @red:
- * @green:
- * @blue:
- * @alpha:
- * @flags: Optional flags for the texture, or %COGL_TEXTURE_NONE;
- * %COGL_TEXTURE_NO_SLICING is useful if the texture will be
- * repeated to create a constant color fill, since hardware
- * repeat can't be used for a sliced texture.
- *
- * Creates a texture that is a single pixel with the specified
- * unpremultiplied color components.
- *
- * Return value: (transfer full): a newly created Cogl texture
- */
-CoglHandle
-meta_create_color_texture_4ub (guint8 red,
- guint8 green,
- guint8 blue,
- guint8 alpha,
- CoglTextureFlags flags)
-{
- CoglColor color;
- guint8 pixel[4];
-
- cogl_color_set_from_4ub (&color, red, green, blue, alpha);
- cogl_color_premultiply (&color);
-
- pixel[0] = cogl_color_get_red_byte (&color);
- pixel[1] = cogl_color_get_green_byte (&color);
- pixel[2] = cogl_color_get_blue_byte (&color);
- pixel[3] = cogl_color_get_alpha_byte (&color);
-
- return cogl_texture_new_from_data (1, 1,
- flags,
- COGL_PIXEL_FORMAT_RGBA_8888_PRE,
- COGL_PIXEL_FORMAT_ANY,
- 4, pixel);
-}
-
+#define CLUTTER_ENABLE_EXPERIMENTAL_API
+#include <clutter/clutter.h>
/* Based on gnome-shell/src/st/st-private.c:_st_create_texture_material.c */
@@ -79,32 +40,69 @@ meta_create_color_texture_4ub (guint8 red,
*
* Return value: (transfer full): a newly created Cogl material
*/
-CoglHandle
+CoglPipeline *
meta_create_texture_material (CoglHandle src_texture)
{
- static CoglHandle texture_material_template = COGL_INVALID_HANDLE;
- CoglHandle material;
-
- /* We use a material that has a dummy texture as a base for all
- texture materials. The idea is that only the Cogl texture object
- would be different in the children so it is likely that Cogl will
- be able to share GL programs between all the textures. */
- if (G_UNLIKELY (texture_material_template == COGL_INVALID_HANDLE))
- {
- CoglHandle dummy_texture;
+ static CoglPipeline *texture_material_template = NULL;
+ CoglPipeline *material;
- dummy_texture = meta_create_color_texture_4ub (0xff, 0xff, 0xff, 0xff,
- COGL_TEXTURE_NONE);
+ if (G_UNLIKELY (texture_material_template == NULL))
+ {
+ ClutterBackend *backend = clutter_get_default_backend ();
+ CoglContext *context = clutter_backend_get_cogl_context (backend);
- texture_material_template = cogl_material_new ();
- cogl_material_set_layer (texture_material_template, 0, dummy_texture);
- cogl_handle_unref (dummy_texture);
+ texture_material_template = cogl_pipeline_new (context);
+ cogl_pipeline_set_layer_null_texture (texture_material_template,
+ 0, COGL_TEXTURE_TYPE_2D);
}
- material = cogl_material_copy (texture_material_template);
+ material = cogl_pipeline_copy (texture_material_template);
if (src_texture != COGL_INVALID_HANDLE)
- cogl_material_set_layer (material, 0, src_texture);
+ cogl_pipeline_set_layer_texture (material, 0, src_texture);
+
+ return material;
+}
+
+/**
+ * meta_create_crossfade_material:
+ * @src_texture_0: (allow-none): the texture to crossfade from
+ * @src_texture_1: (allow-none): the texture to crossfade to
+ *
+ * Creates a material with two layers, using a combine constant to
+ * crossfade between them.
+ *
+ * Return value: (transfer full): a newly created Cogl material
+ */
+CoglPipeline *
+meta_create_crossfade_material (CoglHandle src_texture_0,
+ CoglHandle src_texture_1)
+{
+ static CoglPipeline *texture_material_template = NULL;
+ CoglPipeline *material;
+
+ if (G_UNLIKELY (texture_material_template == NULL))
+ {
+ ClutterBackend *backend = clutter_get_default_backend ();
+ CoglContext *context = clutter_backend_get_cogl_context (backend);
+
+ texture_material_template = cogl_pipeline_new (context);
+
+ cogl_pipeline_set_layer_null_texture (texture_material_template,
+ 0, COGL_TEXTURE_TYPE_2D);
+ cogl_pipeline_set_layer_null_texture (texture_material_template,
+ 1, COGL_TEXTURE_TYPE_2D);
+ cogl_pipeline_set_layer_combine (texture_material_template,
+ 1, "RGBA = INTERPOLATE (TEXTURE, PREVIOUS, CONSTANT[A])",
+ NULL);
+ }
+
+ material = cogl_pipeline_copy (texture_material_template);
+
+ if (src_texture_0 != COGL_INVALID_HANDLE)
+ cogl_pipeline_set_layer_texture (material, 0, src_texture_0);
+ if (src_texture_1 != COGL_INVALID_HANDLE)
+ cogl_pipeline_set_layer_texture (material, 1, src_texture_1);
return material;
}
diff --git a/src/compositor/cogl-utils.h b/src/compositor/cogl-utils.h
index 8d6742e..b13b16f 100644
--- a/src/compositor/cogl-utils.h
+++ b/src/compositor/cogl-utils.h
@@ -23,13 +23,11 @@
#ifndef __META_COGL_UTILS_H__
#define __META_COGL_UTILS_H__
+#define COGL_ENABLE_EXPERIMENTAL_API
#include <cogl/cogl.h>
-CoglHandle meta_create_color_texture_4ub (guint8 red,
- guint8 green,
- guint8 blue,
- guint8 alpha,
- CoglTextureFlags flags);
-CoglHandle meta_create_texture_material (CoglHandle src_texture);
+CoglPipeline *meta_create_texture_material (CoglHandle src_texture);
+CoglPipeline *meta_create_crossfade_material (CoglHandle src_texture_0,
+ CoglHandle src_texture_1);
#endif /* __META_COGL_UTILS_H__ */
diff --git a/src/compositor/compositor.c b/src/compositor/compositor.c
index 105464f..0ab5aa8 100644
--- a/src/compositor/compositor.c
+++ b/src/compositor/compositor.c
@@ -116,21 +116,6 @@ process_property_notify (MetaCompositor *compositor,
{
MetaWindowActor *window_actor;
- if (event->atom == compositor->atom_x_root_pixmap)
- {
- GSList *l;
-
- for (l = meta_display_get_screens (compositor->display); l; l = l->next)
- {
- MetaScreen *screen = l->data;
- if (event->window == meta_screen_get_xroot (screen))
- {
- meta_background_actor_update (screen);
- return;
- }
- }
- }
-
if (window == NULL)
return;
diff --git a/src/compositor/meta-background-actor.c b/src/compositor/meta-background-actor.c
index 00599dd..3a8ff7f 100644
--- a/src/compositor/meta-background-actor.c
+++ b/src/compositor/meta-background-actor.c
@@ -36,6 +36,8 @@
#include <meta/errors.h>
#include "meta-background-actor-private.h"
+#define CROSSFADE_DURATION 1000
+
/* We allow creating multiple MetaBackgroundActors for the same MetaScreen to
* allow different rendering options to be set for different copies.
* But we want to share the same underlying CoglTexture for efficiency and
@@ -57,6 +59,7 @@ struct _MetaScreenBackground
float texture_width;
float texture_height;
+ CoglTexture *old_texture;
CoglTexture *texture;
CoglMaterialWrapMode wrap_mode;
@@ -66,10 +69,14 @@ struct _MetaScreenBackground
struct _MetaBackgroundActorPrivate
{
MetaScreenBackground *background;
+ CoglPipeline *single_pipeline;
+ CoglPipeline *crossfade_pipeline;
CoglPipeline *pipeline;
cairo_region_t *visible_region;
float dim_factor;
+ float crossfade_progress;
+ guint is_crossfading : 1;
};
enum
@@ -77,6 +84,7 @@ enum
PROP_0,
PROP_DIM_FACTOR,
+ PROP_CROSSFADE_PROGRESS,
PROP_LAST
};
@@ -85,6 +93,7 @@ static GParamSpec *obj_props[PROP_LAST];
G_DEFINE_TYPE (MetaBackgroundActor, meta_background_actor, CLUTTER_TYPE_ACTOR);
+static void clear_old_texture (MetaScreenBackground *background);
static void set_texture (MetaScreenBackground *background,
CoglHandle texture);
@@ -152,19 +161,86 @@ meta_screen_background_get (MetaScreen *screen)
}
static void
-update_wrap_mode_of_actor (MetaBackgroundActor *self)
+update_actor_pipeline (MetaBackgroundActor *self,
+ gboolean crossfade)
{
MetaBackgroundActorPrivate *priv = self->priv;
- cogl_pipeline_set_layer_wrap_mode (priv->pipeline, 0, priv->background->wrap_mode);
+ if (crossfade)
+ {
+ priv->pipeline = priv->crossfade_pipeline;
+ priv->is_crossfading = TRUE;
+
+ cogl_pipeline_set_layer_texture (priv->pipeline, 0, priv->background->old_texture);
+ cogl_pipeline_set_layer_wrap_mode (priv->pipeline, 0, priv->background->wrap_mode);
+
+ cogl_pipeline_set_layer_texture (priv->pipeline, 1, priv->background->texture);
+ cogl_pipeline_set_layer_wrap_mode (priv->pipeline, 1, priv->background->wrap_mode);
+ }
+ else
+ {
+ priv->pipeline = priv->single_pipeline;
+ priv->is_crossfading = FALSE;
+
+ cogl_pipeline_set_layer_texture (priv->pipeline, 0, priv->background->texture);
+ cogl_pipeline_set_layer_wrap_mode (priv->pipeline, 0, priv->background->wrap_mode);
+ }
+
+ clutter_actor_queue_redraw (CLUTTER_ACTOR (self));
}
static void
-update_wrap_mode (MetaScreenBackground *background)
+crossfade_completed (ClutterTimeline *timeline,
+ MetaBackgroundActor *actor)
+{
+ clear_old_texture (actor->priv->background);
+ update_actor_pipeline (actor, FALSE);
+}
+
+static void
+clear_old_texture (MetaScreenBackground *background)
+{
+ if (background->old_texture != COGL_INVALID_HANDLE)
+ {
+ cogl_handle_unref (background->old_texture);
+ background->old_texture = COGL_INVALID_HANDLE;
+ }
+}
+
+static void
+set_texture (MetaScreenBackground *background,
+ CoglHandle texture)
{
GSList *l;
+ gboolean crossfade;
int width, height;
+ if (background->old_texture != COGL_INVALID_HANDLE)
+ {
+ cogl_handle_unref (background->old_texture);
+ background->old_texture = COGL_INVALID_HANDLE;
+ }
+
+ if (texture != COGL_INVALID_HANDLE)
+ {
+ background->old_texture = background->texture;
+ background->texture = cogl_handle_ref (texture);
+ }
+ else if (background->texture != COGL_INVALID_HANDLE)
+ {
+ cogl_handle_unref (background->texture);
+ background->texture = COGL_INVALID_HANDLE;
+ }
+
+ if (texture != COGL_INVALID_HANDLE &&
+ background->old_texture != COGL_INVALID_HANDLE)
+ crossfade = TRUE;
+ else
+ crossfade = FALSE;
+
+ background->texture_width = cogl_texture_get_width (background->texture);
+ background->texture_height = cogl_texture_get_height (background->texture);
+
meta_screen_get_size (background->screen, &width, &height);
/* We turn off repeating when we have a full-screen pixmap to keep from
@@ -177,53 +253,55 @@ update_wrap_mode (MetaScreenBackground *background)
background->wrap_mode = COGL_MATERIAL_WRAP_MODE_REPEAT;
for (l = background->actors; l; l = l->next)
- update_wrap_mode_of_actor (l->data);
-}
-
-static void
-set_texture_on_actor (MetaBackgroundActor *self)
-{
- MetaBackgroundActorPrivate *priv = self->priv;
- MetaDisplay *display = meta_screen_get_display (priv->background->screen);
+ {
+ MetaBackgroundActor *actor = l->data;
- /* This may trigger destruction of an old texture pixmap, which, if
- * the underlying X pixmap is already gone has the tendency to trigger
- * X errors inside DRI. For safety, trap errors */
- meta_error_trap_push (display);
- cogl_pipeline_set_layer_texture (priv->pipeline, 0, priv->background->texture);
- meta_error_trap_pop (display);
+ update_actor_pipeline (actor, crossfade);
- clutter_actor_queue_redraw (CLUTTER_ACTOR (self));
+ if (crossfade)
+ {
+ ClutterTransition *transition;
+ ClutterInterval *interval;
+
+ interval = clutter_interval_new (G_TYPE_FLOAT, 0.0, 1.0);
+ transition = g_object_new (CLUTTER_TYPE_PROPERTY_TRANSITION,
+ "animatable", actor,
+ "property-name", "crossfade-progress",
+ "interval", interval,
+ "remove-on-complete", TRUE,
+ "duration", CROSSFADE_DURATION,
+ "progress-mode", CLUTTER_EASE_OUT_QUAD,
+ NULL);
+
+ g_signal_connect_object (transition, "completed",
+ G_CALLBACK (crossfade_completed), actor, 0);
+
+ clutter_actor_remove_transition (CLUTTER_ACTOR (actor), "crossfade");
+ clutter_actor_add_transition (CLUTTER_ACTOR (actor), "crossfade",
+ transition);
+ }
+ }
}
static void
-set_texture (MetaScreenBackground *background,
- CoglHandle texture)
+update_wrap_mode (MetaScreenBackground *background)
{
- MetaDisplay *display = meta_screen_get_display (background->screen);
GSList *l;
+ int width, height;
- /* This may trigger destruction of an old texture pixmap, which, if
- * the underlying X pixmap is already gone has the tendency to trigger
- * X errors inside DRI. For safety, trap errors */
- meta_error_trap_push (display);
- if (background->texture != COGL_INVALID_HANDLE)
- {
- cogl_handle_unref (background->texture);
- background->texture = COGL_INVALID_HANDLE;
- }
- meta_error_trap_pop (display);
-
- if (texture != COGL_INVALID_HANDLE)
- background->texture = cogl_handle_ref (texture);
+ meta_screen_get_size (background->screen, &width, &height);
- background->texture_width = cogl_texture_get_width (background->texture);
- background->texture_height = cogl_texture_get_height (background->texture);
+ if (width == background->texture_width && height == background->texture_height)
+ background->wrap_mode = COGL_MATERIAL_WRAP_MODE_CLAMP_TO_EDGE;
+ else
+ background->wrap_mode = COGL_MATERIAL_WRAP_MODE_REPEAT;
- for (l = background->actors; l; l = l->next)
- set_texture_on_actor (l->data);
+ for (l = background->actors; l != NULL; l++)
+ {
+ MetaBackgroundActor *actor = l->data;
- update_wrap_mode (background);
+ update_actor_pipeline (actor, actor->priv->is_crossfading);
+ }
}
static inline void
@@ -250,7 +328,8 @@ meta_background_actor_dispose (GObject *object)
priv->background = NULL;
}
- g_clear_pointer(&priv->pipeline, cogl_object_unref);
+ g_clear_pointer(&priv->single_pipeline, cogl_object_unref);
+ g_clear_pointer(&priv->crossfade_pipeline, cogl_object_unref);
G_OBJECT_CLASS (meta_background_actor_parent_class)->dispose (object);
}
@@ -300,6 +379,7 @@ meta_background_actor_paint (ClutterActor *actor)
guint8 opacity = clutter_actor_get_paint_opacity (actor);
guint8 color_component;
int width, height;
+ CoglColor crossfade_color;
meta_background_ensure_rendered (priv->background);
@@ -313,6 +393,17 @@ meta_background_actor_paint (ClutterActor *actor)
color_component,
opacity);
+ if (priv->is_crossfading)
+ {
+ cogl_color_init_from_4f (&crossfade_color,
+ priv->crossfade_progress,
+ priv->crossfade_progress,
+ priv->crossfade_progress,
+ priv->crossfade_progress);
+ cogl_pipeline_set_layer_combine_constant (priv->pipeline,
+ 1, &crossfade_color);
+ }
+
cogl_set_source (priv->pipeline);
if (priv->visible_region)
@@ -360,6 +451,22 @@ meta_background_actor_get_paint_volume (ClutterActor *actor,
}
static void
+meta_background_actor_set_crossfade_progress (MetaBackgroundActor *self,
+ gfloat crossfade_progress)
+{
+ MetaBackgroundActorPrivate *priv = self->priv;
+
+ if (priv->crossfade_progress == crossfade_progress)
+ return;
+
+ priv->crossfade_progress = crossfade_progress;
+
+ clutter_actor_queue_redraw (CLUTTER_ACTOR (self));
+
+ g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CROSSFADE_PROGRESS]);
+}
+
+static void
meta_background_actor_set_dim_factor (MetaBackgroundActor *self,
gfloat dim_factor)
{
@@ -389,6 +496,8 @@ meta_background_actor_get_property(GObject *object,
case PROP_DIM_FACTOR:
g_value_set_float (value, priv->dim_factor);
break;
+ case PROP_CROSSFADE_PROGRESS:
+ g_value_set_float (value, priv->crossfade_progress);
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -408,6 +517,9 @@ meta_background_actor_set_property(GObject *object,
case PROP_DIM_FACTOR:
meta_background_actor_set_dim_factor (self, g_value_get_float (value));
break;
+ case PROP_CROSSFADE_PROGRESS:
+ meta_background_actor_set_crossfade_progress (self, g_value_get_float (value));
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -445,7 +557,18 @@ meta_background_actor_class_init (MetaBackgroundActorClass *klass)
1.0,
G_PARAM_READWRITE);
obj_props[PROP_DIM_FACTOR] = pspec;
- g_object_class_install_property (object_class, PROP_DIM_FACTOR, pspec);
+
+ /**
+ * MetaBackgroundActor:crossfade-progress: (skip)
+ */
+ pspec = g_param_spec_float ("crossfade-progress",
+ "", "",
+ 0.0, 1.0,
+ 1.0,
+ G_PARAM_READWRITE);
+ obj_props[PROP_CROSSFADE_PROGRESS] = pspec;
+
+ g_object_class_install_properties (object_class, PROP_LAST, obj_props);
}
static void
@@ -481,11 +604,12 @@ meta_background_actor_new_for_screen (MetaScreen *screen)
priv->background = meta_screen_background_get (screen);
priv->background->actors = g_slist_prepend (priv->background->actors, self);
- /* A CoglMaterial and a CoglPipeline are the same thing */
- priv->pipeline = (CoglPipeline*) meta_create_texture_material (NULL);
+ priv->single_pipeline = meta_create_texture_material (priv->background->texture);
+ priv->crossfade_pipeline = meta_create_crossfade_material (priv->background->old_texture,
+ priv->background->texture);
- set_texture_on_actor (self);
- update_wrap_mode_of_actor (self);
+ if (priv->background->texture != COGL_INVALID_HANDLE)
+ update_actor_pipeline (self, FALSE);
return CLUTTER_ACTOR (self);
}
@@ -522,7 +646,7 @@ on_background_drawn (GObject *object,
}
else
{
- g_warning ("Failed to create background texture from pixmap: %s",
+ g_warning ("Failed to render background: %s",
error->message);
g_error_free (error);
}
@@ -652,9 +776,17 @@ meta_background_actor_add_glsl_snippet (MetaBackgroundActor *actor,
if (hook == META_SNIPPET_HOOK_VERTEX ||
hook == META_SNIPPET_HOOK_FRAGMENT)
- cogl_pipeline_add_snippet (priv->pipeline, snippet);
+ {
+ cogl_pipeline_add_snippet (priv->single_pipeline, snippet);
+ cogl_pipeline_add_snippet (priv->crossfade_pipeline, snippet);
+ }
else
- cogl_pipeline_add_layer_snippet (priv->pipeline, 0, snippet);
+ {
+ /* In case of crossfading, apply the snippet only to the new texture.
+ We can't apply it to both because declarations would be doubled. */
+ cogl_pipeline_add_layer_snippet (priv->single_pipeline, 0, snippet);
+ cogl_pipeline_add_layer_snippet (priv->crossfade_pipeline, 1, snippet);
+ }
cogl_object_unref (snippet);
}
@@ -688,8 +820,12 @@ meta_background_actor_set_uniform_float (MetaBackgroundActor *actor,
priv = actor->priv;
- cogl_pipeline_set_uniform_float (priv->pipeline,
- cogl_pipeline_get_uniform_location (priv->pipeline,
+ cogl_pipeline_set_uniform_float (priv->single_pipeline,
+ cogl_pipeline_get_uniform_location (priv->single_pipeline,
+ uniform_name),
+ n_components, count, uniform);
+ cogl_pipeline_set_uniform_float (priv->crossfade_pipeline,
+ cogl_pipeline_get_uniform_location (priv->crossfade_pipeline,
uniform_name),
n_components, count, uniform);
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]