From 0e9a1dee6dde18e7fe6d92960987baa933826937 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Mon, 17 May 2010 12:55:46 +0100 Subject: [PATCH] shader-effect: Simplify setting the shader source Sub-classes of ShaderEffect currently have to get the handle for the Cogl shader and call cogl_shader_source(); this makes it awkward to implement a ShaderEffect, and it exposes handles and Cogl API that we might want to change in the future. We should provide a ClutterShaderEffect method that allows to (safely) set the shader source at the right time for sub-classes to use. --- clutter/clutter-blur-effect.c | 13 +--- clutter/clutter-colorize-effect.c | 15 +--- clutter/clutter-desaturate-effect.c | 15 +--- clutter/clutter-shader-effect.c | 116 +++++++++++++++------------- clutter/clutter-shader-effect.h | 23 +++--- 5 files changed, 81 insertions(+), 101 deletions(-) diff --git a/clutter/clutter-blur-effect.c b/clutter/clutter-blur-effect.c index 8b1d0ddef..3ec60cc3f 100644 --- a/clutter/clutter-blur-effect.c +++ b/clutter/clutter-blur-effect.c @@ -94,8 +94,6 @@ struct _ClutterBlurEffect */ gfloat x_step; gfloat y_step; - - guint source_set : 1; }; struct _ClutterBlurEffectClass @@ -147,16 +145,7 @@ clutter_blur_effect_pre_paint (ClutterEffect *effect) shader_effect = CLUTTER_SHADER_EFFECT (effect); - if (!self->source_set) - { - CoglHandle shader = clutter_shader_effect_get_shader (shader_effect); - - if (shader == COGL_INVALID_HANDLE) - return FALSE; - - cogl_shader_source (shader, box_blur_glsl_shader); - self->source_set = TRUE; - } + clutter_shader_effect_set_shader_source (shader_effect, box_blur_glsl_shader); clutter_shader_effect_set_uniform (shader_effect, "tex", diff --git a/clutter/clutter-colorize-effect.c b/clutter/clutter-colorize-effect.c index e229ee2da..b19ea2876 100644 --- a/clutter/clutter-colorize-effect.c +++ b/clutter/clutter-colorize-effect.c @@ -65,8 +65,6 @@ struct _ClutterColorizeEffect /* the tint of the colorization */ ClutterColor tint; - - guint source_set : 1; }; struct _ClutterColorizeEffectClass @@ -114,17 +112,12 @@ clutter_colorize_effect_pre_paint (ClutterEffect *effect) ClutterEffectClass *parent_class; float tint_r, tint_g, tint_b; + if (!clutter_actor_meta_get_enabled (CLUTTER_ACTOR_META (effect))) + return FALSE; + shader_effect = CLUTTER_SHADER_EFFECT (effect); - if (!self->source_set) - { - CoglHandle shader = clutter_shader_effect_get_shader (shader_effect); - if (shader == COGL_INVALID_HANDLE) - return FALSE; - - cogl_shader_source (shader, colorize_glsl_shader); - self->source_set = TRUE; - } + clutter_shader_effect_set_shader_source (shader_effect, colorize_glsl_shader); /* we want normalized values here */ tint_r = self->tint.red / 255.0f; diff --git a/clutter/clutter-desaturate-effect.c b/clutter/clutter-desaturate-effect.c index 1a81e370d..bfd6ca54b 100644 --- a/clutter/clutter-desaturate-effect.c +++ b/clutter/clutter-desaturate-effect.c @@ -67,8 +67,6 @@ struct _ClutterDesaturateEffect /* the desaturation factor, also known as "strength" */ gdouble factor; - - guint source_set : 1; }; struct _ClutterDesaturateEffectClass @@ -129,18 +127,7 @@ clutter_desaturate_effect_pre_paint (ClutterEffect *effect) shader_effect = CLUTTER_SHADER_EFFECT (effect); - if (!self->source_set) - { - CoglHandle shader; - - /* get the CoglShader handle to set the source */ - shader = clutter_shader_effect_get_shader (shader_effect); - if (shader == COGL_INVALID_HANDLE) - return FALSE; - - cogl_shader_source (shader, desaturate_glsl_shader); - self->source_set = TRUE; - } + clutter_shader_effect_set_shader_source (shader_effect, desaturate_glsl_shader); factor = (float) self->factor; diff --git a/clutter/clutter-shader-effect.c b/clutter/clutter-shader-effect.c index 2a48df786..0f68151a1 100644 --- a/clutter/clutter-shader-effect.c +++ b/clutter/clutter-shader-effect.c @@ -38,51 +38,14 @@ * * Implementing a ClutterShaderEffect * Creating a sub-class of #ClutterShaderEffect requires the - * overriding of the set_actor() virtual function - * from the #ClutterActorMeta class, and the pre_paint() - * virtual functions from the #ClutterEffect class. - * The set_actor() must chain up to the - * #ClutterShaderEffect implementation; if the effect has not been disabled - * by the super class implementation, then the sub-class should get the - * #CoglHandle for the fragment shader using - * clutter_shader_effect_get_shader() and call cogl_shader_source() to set - * the source of the program. - * - * Preparing a ClutterShaderEffect - * The example below shows the typical implementation of the - * set_actor() phase of a #ClutterShaderEffect - * sub-class. - * - * static void - * my_effect_set_actor (ClutterActorMeta *meta, - * ClutterActor *actor) - * { - * MyEffect *self = MY_EFFECT (meta); - * ClutterActorMetaClass *parent_class; - * CoglHandle handle; - * - * /* chain up to the parent's implementation */ - * parent_class = CLUTTER_EFFECT_CLASS (my_effect_parent_class); - * parent_class->set_actor (meta, actor)); - * - * /* if the parent class disabled the effect then we return * - * if (!clutter_actor_meta_get_enabled (meta)) - * return; - * - * /* we should have a handle to the shader at this point */ - * handle = clutter_shader_effect_get_shader (CLUTTER_SHADER_EFFECT (self)); - * if (handle == COGL_INVALID_HANDLE) - * return; - * - * /* set the source of the shader */ - * cogl_shader_source (handle, my_effect_glsl_source); - * } - * - * - * The pre_paint() is optional and it depends on - * whether the fragment shader has uniforms to set. The sub-class should call - * clutter_shader_effect_set_uniform_value() or - * clutter_shader_effect_set_uniform() and then chain up to the + * overriding of the pre_paint() virtual function + * from the #ClutterEffect class. + * The pre_paint() should set the shader's + * source and eventually set the uniforms. The sub-class should call + * clutter_shader_effect_set_shader_source() to set the shader source + * code, and clutter_shader_effect_set_uniform_value() or + * clutter_shader_effect_set_uniform() to set the values of the shader + * uniforms, if any; the sub-class should then chain up to the * #ClutterShaderEffect implementation. * * Setting uniforms on a ClutterShaderEffect @@ -98,11 +61,13 @@ * ClutterEffectClass *parent_class; * gfloat component_r, component_g, component_b; * - * /* chain up to the parent's implementation */ - * parent_class = CLUTTER_EFFECT_CLASS (my_effect_parent_class); - * if (!parent_class->pre_paint (effect)) + * /* if the effect is not enabled we can bail out now */ + * if (!clutter_actor_meta_get_enabled (CLUTTER_ACTOR_META (effect))) * return FALSE; * + * /* this function is a no-op after the first call */ + * clutter_shader_effect_set_shader_source (shader, shader_source); + * * /* the "tex" uniform is declared in the shader as: * * * * uniform int tex; @@ -127,7 +92,9 @@ * component_g, * component_b); * - * return TRUE; + * /* chain up to the parent's implementation */ + * parent_class = CLUTTER_EFFECT_CLASS (my_effect_parent_class); + * return parent_class->pre_paint (effect); * } * * @@ -167,6 +134,7 @@ struct _ClutterShaderEffectPrivate GHashTable *uniforms; guint is_compiled : 1; + guint source_set : 1; }; G_DEFINE_ABSTRACT_TYPE (ClutterShaderEffect, @@ -199,6 +167,7 @@ clutter_shader_effect_clear (ClutterShaderEffect *effect, priv->actor = NULL; priv->is_compiled = FALSE; + priv->source_set = FALSE; } static void @@ -289,8 +258,6 @@ clutter_shader_effect_set_actor (ClutterActorMeta *meta, ClutterShaderEffect *self = CLUTTER_SHADER_EFFECT (meta); ClutterShaderEffectPrivate *priv = self->priv; ClutterActorMetaClass *parent; - ClutterActorBox allocation; - gfloat width, height; if (!clutter_feature_available (CLUTTER_FEATURE_SHADERS_GLSL)) { @@ -318,9 +285,6 @@ clutter_shader_effect_set_actor (ClutterActorMeta *meta, CLUTTER_NOTE (SHADER, "Preparing shader effect of type '%s'", G_OBJECT_TYPE_NAME (meta)); - clutter_actor_get_allocation_box (priv->actor, &allocation); - clutter_actor_box_get_size (&allocation, &width, &height); - priv->program = cogl_create_program (); priv->shader = cogl_create_shader (COGL_SHADER_TYPE_FRAGMENT); @@ -340,6 +304,9 @@ clutter_shader_effect_paint_target (ClutterOffscreenEffect *effect) priv->shader == COGL_INVALID_HANDLE) return; + if (!priv->source_set) + return; + if (!priv->is_compiled) { CLUTTER_NOTE (SHADER, "Compiling shader effect"); @@ -757,3 +724,44 @@ clutter_shader_effect_set_uniform (ClutterShaderEffect *effect, &args); va_end (args); } + +/** + * clutter_shader_effect_set_shader_source: + * @effect: a #ClutterShaderEffect + * @source: the source of a GLSL shader + * + * Sets the source of the GLSL shader used by @effect + * + * This function should only be called by implementations of + * the #ClutterShaderEffect class, and not by application code. + * + * This function can only be called once; subsequent calls will + * yield no result. + * + * Return value: %TRUE if the source was set + * + * Since: 1.4 + */ +gboolean +clutter_shader_effect_set_shader_source (ClutterShaderEffect *effect, + const gchar *source) +{ + ClutterShaderEffectPrivate *priv; + + g_return_val_if_fail (CLUTTER_IS_SHADER_EFFECT (effect), FALSE); + g_return_val_if_fail (source != NULL && *source != '\0', FALSE); + + priv = effect->priv; + + if (priv->source_set) + return TRUE; + + if (priv->shader == COGL_INVALID_HANDLE) + return FALSE; + + cogl_shader_source (priv->shader, source); + + priv->source_set = TRUE; + + return TRUE; +} diff --git a/clutter/clutter-shader-effect.h b/clutter/clutter-shader-effect.h index 71540bbb7..40fa20c33 100644 --- a/clutter/clutter-shader-effect.h +++ b/clutter/clutter-shader-effect.h @@ -84,17 +84,20 @@ struct _ClutterShaderEffectClass GType clutter_shader_effect_get_type (void) G_GNUC_CONST; -void clutter_shader_effect_set_uniform (ClutterShaderEffect *effect, - const gchar *name, - GType gtype, - gsize size, - ...); -void clutter_shader_effect_set_uniform_value (ClutterShaderEffect *effect, - const gchar *name, - const GValue *value); +gboolean clutter_shader_effect_set_shader_source (ClutterShaderEffect *effect, + const gchar *source); -CoglHandle clutter_shader_effect_get_shader (ClutterShaderEffect *effect); -CoglHandle clutter_shader_effect_get_program (ClutterShaderEffect *effect); +void clutter_shader_effect_set_uniform (ClutterShaderEffect *effect, + const gchar *name, + GType gtype, + gsize size, + ...); +void clutter_shader_effect_set_uniform_value (ClutterShaderEffect *effect, + const gchar *name, + const GValue *value); + +CoglHandle clutter_shader_effect_get_shader (ClutterShaderEffect *effect); +CoglHandle clutter_shader_effect_get_program (ClutterShaderEffect *effect); G_END_DECLS