summaryrefslogtreecommitdiff
path: root/clutter/clutter-blur-effect.c
diff options
context:
space:
mode:
authorEmmanuele Bassi <ebassi@linux.intel.com>2010-08-11 13:05:42 +0100
committerEmmanuele Bassi <ebassi@linux.intel.com>2010-08-11 14:21:23 +0100
commit7daeb217bd9f1e0e38ac6201f722bdc7fd2c45b6 (patch)
tree6e616ab9999ba5aae442a911f7c86d19937ffc9a /clutter/clutter-blur-effect.c
parenteb4dee46b70a73d0926e8e36bb75abc52604256e (diff)
downloadclutter-7daeb217bd9f1e0e38ac6201f722bdc7fd2c45b6.tar.gz
blur-effect: Do not inherit from ShaderEffect
We might want to switch the BlurEffect from a box-blur to a super-sampling of the texture target, in order to make it cheap(er). If we inherit from ShaderEffect, though, we're setting in stone the fact that we are going to use a fragment shader for blurring. Since there is not parametrization of the blur, the code necessary to implement effect is pretty small, and we can use the Cogl API directly.
Diffstat (limited to 'clutter/clutter-blur-effect.c')
-rw-r--r--clutter/clutter-blur-effect.c157
1 files changed, 103 insertions, 54 deletions
diff --git a/clutter/clutter-blur-effect.c b/clutter/clutter-blur-effect.c
index 19f428bef..c25370c11 100644
--- a/clutter/clutter-blur-effect.c
+++ b/clutter/clutter-blur-effect.c
@@ -30,10 +30,6 @@
* #ClutterBlurEffect is a sub-class of #ClutterEffect that allows blurring a
* actor and its contents.
*
- * #ClutterBlurEffect uses the programmable pipeline of the GPU and an
- * offscreen buffer, so it is only available on graphics hardware that supports
- * these two features.
- *
* #ClutterBlurEffect is available since Clutter 1.4
*/
@@ -50,8 +46,8 @@
#include "cogl/cogl.h"
#include "clutter-debug.h"
+#include "clutter-offscreen-effect.h"
#include "clutter-private.h"
-#include "clutter-shader-effect.h"
typedef struct _ClutterBlurEffectClass ClutterBlurEffectClass;
@@ -85,7 +81,7 @@ static const gchar *box_blur_glsl_shader =
struct _ClutterBlurEffect
{
- ClutterShaderEffect parent_instance;
+ ClutterOffscreenEffect parent_instance;
/* a back pointer to our actor, so that we can query it */
ClutterActor *actor;
@@ -95,21 +91,25 @@ struct _ClutterBlurEffect
*/
gfloat x_step;
gfloat y_step;
-};
-struct _ClutterBlurEffectClass
-{
- ClutterShaderEffectClass parent_class;
+ CoglHandle shader;
+ CoglHandle program;
+
+ gint tex_uniform;
+ gint x_step_uniform;
+ gint y_step_uniform;
+
+ guint is_compiled : 1;
};
-enum
+struct _ClutterBlurEffectClass
{
- PROP_0
+ ClutterOffscreenEffectClass parent_class;
};
G_DEFINE_TYPE (ClutterBlurEffect,
clutter_blur_effect,
- CLUTTER_TYPE_SHADER_EFFECT);
+ CLUTTER_TYPE_OFFSCREEN_EFFECT);
static int
next_p2 (int a)
@@ -126,7 +126,6 @@ static gboolean
clutter_blur_effect_pre_paint (ClutterEffect *effect)
{
ClutterBlurEffect *self = CLUTTER_BLUR_EFFECT (effect);
- ClutterShaderEffect *shader_effect;
ClutterEffectClass *parent_class;
ClutterActorBox allocation;
gfloat width, height;
@@ -144,59 +143,107 @@ clutter_blur_effect_pre_paint (ClutterEffect *effect)
self->x_step = 1.0f / (float) next_p2 (width);
self->y_step = 1.0f / (float) next_p2 (height);
- shader_effect = CLUTTER_SHADER_EFFECT (effect);
+ if (self->shader == COGL_INVALID_HANDLE)
+ {
+ self->shader = cogl_create_shader (COGL_SHADER_TYPE_FRAGMENT);
+ cogl_shader_source (self->shader, box_blur_glsl_shader);
- clutter_shader_effect_set_shader_source (shader_effect, box_blur_glsl_shader);
+ self->is_compiled = FALSE;
+ self->tex_uniform = -1;
+ self->x_step_uniform = -1;
+ self->y_step_uniform = -1;
+ }
+
+ if (self->program == COGL_INVALID_HANDLE)
+ self->program = cogl_create_program ();
- clutter_shader_effect_set_uniform (shader_effect,
- "tex",
- G_TYPE_INT, 1,
- 0);
- clutter_shader_effect_set_uniform (shader_effect,
- "x_step",
- G_TYPE_FLOAT, 1,
- self->x_step);
- clutter_shader_effect_set_uniform (shader_effect,
- "y_step",
- G_TYPE_FLOAT, 1,
- self->y_step);
+ if (!self->is_compiled)
+ {
+ g_assert (self->shader != COGL_INVALID_HANDLE);
+ g_assert (self->program != COGL_INVALID_HANDLE);
+
+ cogl_shader_compile (self->shader);
+ if (!cogl_shader_is_compiled (self->shader))
+ {
+ gchar *log_buf = cogl_shader_get_info_log (self->shader);
+
+ g_warning (G_STRLOC ": Unable to compile the box blur shader: %s",
+ log_buf);
+ g_free (log_buf);
+
+ cogl_handle_unref (self->shader);
+ cogl_handle_unref (self->program);
+
+ self->shader = COGL_INVALID_HANDLE;
+ self->program = COGL_INVALID_HANDLE;
+ }
+ else
+ {
+ cogl_program_attach_shader (self->program, self->shader);
+ cogl_program_link (self->program);
+
+ cogl_handle_unref (self->shader);
+
+ self->is_compiled = TRUE;
+
+ self->tex_uniform =
+ cogl_program_get_uniform_location (self->program, "tex");
+ self->x_step_uniform =
+ cogl_program_get_uniform_location (self->program, "x_step");
+ self->y_step_uniform =
+ cogl_program_get_uniform_location (self->program, "y_step");
+ }
+ }
parent_class = CLUTTER_EFFECT_CLASS (clutter_blur_effect_parent_class);
return parent_class->pre_paint (effect);
}
static void
-clutter_blur_effect_finalize (GObject *gobject)
+clutter_blur_effect_paint_target (ClutterOffscreenEffect *effect)
{
- G_OBJECT_CLASS (clutter_blur_effect_parent_class)->finalize (gobject);
-}
+ ClutterBlurEffect *self = CLUTTER_BLUR_EFFECT (effect);
+ ClutterOffscreenEffectClass *parent;
+ CoglHandle material;
-static void
-clutter_blur_effect_set_property (GObject *gobject,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- switch (prop_id)
- {
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
- break;
- }
+ if (self->program == COGL_INVALID_HANDLE)
+ goto out;
+
+ cogl_program_use (self->program);
+
+ if (self->tex_uniform > -1)
+ cogl_program_uniform_1i (self->tex_uniform, 0);
+
+ if (self->x_step_uniform > -1)
+ cogl_program_uniform_1f (self->x_step_uniform, self->x_step);
+
+ if (self->y_step_uniform > -1)
+ cogl_program_uniform_1f (self->y_step_uniform, self->y_step);
+
+ cogl_program_use (COGL_INVALID_HANDLE);
+
+ material = clutter_offscreen_effect_get_target (effect);
+ cogl_material_set_user_program (material, self->program);
+
+out:
+ parent = CLUTTER_OFFSCREEN_EFFECT_CLASS (clutter_blur_effect_parent_class);
+ parent->paint_target (effect);
}
static void
-clutter_blur_effect_get_property (GObject *gobject,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
+clutter_blur_effect_dispose (GObject *gobject)
{
- switch (prop_id)
+ ClutterBlurEffect *self = CLUTTER_BLUR_EFFECT (gobject);
+
+ if (self->program != COGL_INVALID_HANDLE)
{
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
- break;
+ cogl_handle_unref (self->program);
+
+ self->program = COGL_INVALID_HANDLE;
+ self->shader = COGL_INVALID_HANDLE;
}
+
+ G_OBJECT_CLASS (clutter_blur_effect_parent_class)->dispose (gobject);
}
static void
@@ -204,12 +251,14 @@ clutter_blur_effect_class_init (ClutterBlurEffectClass *klass)
{
ClutterEffectClass *effect_class = CLUTTER_EFFECT_CLASS (klass);
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ ClutterOffscreenEffectClass *offscreen_class;
+
+ gobject_class->dispose = clutter_blur_effect_dispose;
effect_class->pre_paint = clutter_blur_effect_pre_paint;
- gobject_class->set_property = clutter_blur_effect_set_property;
- gobject_class->get_property = clutter_blur_effect_get_property;
- gobject_class->finalize = clutter_blur_effect_finalize;
+ offscreen_class = CLUTTER_OFFSCREEN_EFFECT_CLASS (klass);
+ offscreen_class->paint_target = clutter_blur_effect_paint_target;
}
static void