shell: Actually make GLSLEffect an effect

A generic, introspectable Shader effect is not only more flexible
than a shader actor, it will also make it much easier to turn
Lightbox into an actor subclass and replace Tweener with Clutter's
own animation support.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/651
This commit is contained in:
Florian Müllner 2019-07-26 22:08:52 +02:00
parent ae7ec648b2
commit 007d305736
3 changed files with 70 additions and 32 deletions

View File

@ -24,8 +24,8 @@ t = clamp(t, 0.0, 1.0);\n\
float pixel_brightness = mix(1.0, 1.0 - vignette_sharpness, t);\n\ float pixel_brightness = mix(1.0, 1.0 - vignette_sharpness, t);\n\
cogl_color_out.a = cogl_color_out.a * (1 - pixel_brightness * brightness);'; cogl_color_out.a = cogl_color_out.a * (1 - pixel_brightness * brightness);';
var RadialShaderQuad = GObject.registerClass( var RadialShaderEffect = GObject.registerClass(
class RadialShaderQuad extends Shell.GLSLEffect { class RadialShaderEffect extends Shell.GLSLEffect {
_init(params) { _init(params) {
super._init(params); super._init(params);
@ -99,12 +99,13 @@ var Lightbox = class Lightbox {
this._children = container.get_children(); this._children = container.get_children();
this._fadeFactor = params.fadeFactor; this._fadeFactor = params.fadeFactor;
this._radialEffect = Clutter.feature_available(Clutter.FeatureFlags.SHADERS_GLSL) && params.radialEffect; this._radialEffect = Clutter.feature_available(Clutter.FeatureFlags.SHADERS_GLSL) && params.radialEffect;
this.actor = new St.Bin({ reactive: params.inhibitEvents });
if (this._radialEffect) if (this._radialEffect)
this.actor = new RadialShaderQuad({ reactive: params.inhibitEvents }); this.actor.add_effect(new RadialShaderEffect({ name: 'radial' }));
else else
this.actor = new St.Bin({ opacity: 0, this.actor.set({ opacity: 0, style_class: 'lightbox' });
style_class: 'lightbox',
reactive: params.inhibitEvents });
container.add_actor(this.actor); container.add_actor(this.actor);
this.actor.raise_top(); this.actor.raise_top();
@ -155,7 +156,7 @@ var Lightbox = class Lightbox {
Tweener.removeTweens(this.actor); Tweener.removeTweens(this.actor);
if (this._radialEffect) { if (this._radialEffect) {
Tweener.addTween(this.actor, Tweener.addTween(this.actor.get_effect('radial'),
{ brightness: VIGNETTE_BRIGHTNESS, { brightness: VIGNETTE_BRIGHTNESS,
vignetteSharpness: VIGNETTE_SHARPNESS, vignetteSharpness: VIGNETTE_SHARPNESS,
time: fadeInTime, time: fadeInTime,
@ -186,7 +187,7 @@ var Lightbox = class Lightbox {
this.shown = false; this.shown = false;
Tweener.removeTweens(this.actor); Tweener.removeTweens(this.actor);
if (this._radialEffect) { if (this._radialEffect) {
Tweener.addTween(this.actor, Tweener.addTween(this.actor.get_effect('radial'),
{ brightness: 1.0, { brightness: 1.0,
vignetteSharpness: 0.0, vignetteSharpness: 0.0,
opacity: 0, opacity: 0,

View File

@ -2,13 +2,11 @@
/** /**
* SECTION:shell-glsl-effect * SECTION:shell-glsl-effect
* @short_description: Draw a rectangle using GLSL * @short_description: An offscreen effect using GLSL
* *
* A #ShellGLSLEffect draws one single rectangle, sized to the allocation * A #ShellGLSLEffect is a #ClutterOffscreenEffect that allows
* box, but allows running custom GLSL to the vertex and fragment * running custom GLSL to the vertex and fragment stages of the
* stages of the graphic pipeline. * graphic pipeline.
*
* To ease writing the shader, a single texture layer is also used.
*/ */
#include "config.h" #include "config.h"
@ -20,29 +18,65 @@ typedef struct _ShellGLSLEffectPrivate ShellGLSLEffectPrivate;
struct _ShellGLSLEffectPrivate struct _ShellGLSLEffectPrivate
{ {
CoglPipeline *pipeline; CoglPipeline *pipeline;
gint tex_width;
gint tex_height;
}; };
G_DEFINE_TYPE_WITH_PRIVATE (ShellGLSLEffect, shell_glsl_effect, CLUTTER_TYPE_ACTOR); G_DEFINE_TYPE_WITH_PRIVATE (ShellGLSLEffect, shell_glsl_effect, CLUTTER_TYPE_OFFSCREEN_EFFECT);
static gboolean static gboolean
shell_glsl_effect_get_paint_volume (ClutterActor *actor, shell_glsl_effect_pre_paint (ClutterEffect *effect)
ClutterPaintVolume *volume)
{ {
return clutter_paint_volume_set_from_allocation (volume, actor); ShellGLSLEffect *self = SHELL_GLSL_EFFECT (effect);
ClutterOffscreenEffect *offscreen_effect = CLUTTER_OFFSCREEN_EFFECT (effect);
ShellGLSLEffectPrivate *priv = shell_glsl_effect_get_instance_private (self);
ClutterEffectClass *parent_class;
CoglHandle texture;
gboolean success;
if (!clutter_actor_meta_get_enabled (CLUTTER_ACTOR_META (effect)))
return FALSE;
if (!clutter_feature_available (CLUTTER_FEATURE_SHADERS_GLSL))
{
/* if we don't have support for GLSL shaders then we
* forcibly disable the ActorMeta
*/
g_warning ("Unable to use the ShaderEffect: the graphics hardware "
"or the current GL driver does not implement support "
"for the GLSL shading language.");
clutter_actor_meta_set_enabled (CLUTTER_ACTOR_META (effect), FALSE);
return FALSE;
}
parent_class = CLUTTER_EFFECT_CLASS (shell_glsl_effect_parent_class);
success = parent_class->pre_paint (effect);
if (!success)
return FALSE;
texture = clutter_offscreen_effect_get_texture (offscreen_effect);
priv->tex_width = cogl_texture_get_width (texture);
priv->tex_height = cogl_texture_get_height (texture);
cogl_pipeline_set_layer_texture (priv->pipeline, 0, texture);
return TRUE;
} }
static void static void
shell_glsl_effect_paint (ClutterActor *actor) shell_glsl_effect_paint_target (ClutterOffscreenEffect *effect)
{ {
ShellGLSLEffect *self = SHELL_GLSL_EFFECT (actor); ShellGLSLEffect *self = SHELL_GLSL_EFFECT (effect);
ShellGLSLEffectPrivate *priv; ShellGLSLEffectPrivate *priv;
ClutterActor *actor;
guint8 paint_opacity; guint8 paint_opacity;
ClutterActorBox box;
priv = shell_glsl_effect_get_instance_private (self); priv = shell_glsl_effect_get_instance_private (self);
actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (effect));
paint_opacity = clutter_actor_get_paint_opacity (actor); paint_opacity = clutter_actor_get_paint_opacity (actor);
clutter_actor_get_allocation_box (actor, &box);
cogl_pipeline_set_color4ub (priv->pipeline, cogl_pipeline_set_color4ub (priv->pipeline,
paint_opacity, paint_opacity,
@ -51,8 +85,8 @@ shell_glsl_effect_paint (ClutterActor *actor)
paint_opacity); paint_opacity);
cogl_framebuffer_draw_rectangle (cogl_get_draw_framebuffer (), cogl_framebuffer_draw_rectangle (cogl_get_draw_framebuffer (),
priv->pipeline, priv->pipeline,
box.x1, box.y1, 0, 0,
box.x2, box.y2); priv->tex_width, priv->tex_height);
} }
@ -64,7 +98,7 @@ shell_glsl_effect_paint (ClutterActor *actor)
* @code: GLSL code * @code: GLSL code
* @is_replace: wheter Cogl code should be replaced by the custom shader * @is_replace: wheter Cogl code should be replaced by the custom shader
* *
* Adds a GLSL snippet to the pipeline used for drawing the actor texture. * Adds a GLSL snippet to the pipeline used for drawing the effect texture.
* See #CoglSnippet for details. * See #CoglSnippet for details.
* *
* This is only valid inside the a call to the build_pipeline() virtual * This is only valid inside the a call to the build_pipeline() virtual
@ -149,20 +183,23 @@ shell_glsl_effect_constructed (GObject *object)
priv->pipeline = cogl_pipeline_copy (klass->base_pipeline); priv->pipeline = cogl_pipeline_copy (klass->base_pipeline);
cogl_pipeline_set_layer_null_texture (priv->pipeline, 0); cogl_pipeline_set_layer_null_texture (klass->base_pipeline, 0);
} }
static void static void
shell_glsl_effect_class_init (ShellGLSLEffectClass *klass) shell_glsl_effect_class_init (ShellGLSLEffectClass *klass)
{ {
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass); ClutterEffectClass *effect_class = CLUTTER_EFFECT_CLASS (klass);
GObjectClass *gobject_class = G_OBJECT_CLASS (klass); GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
ClutterOffscreenEffectClass *offscreen_class;
offscreen_class = CLUTTER_OFFSCREEN_EFFECT_CLASS (klass);
offscreen_class->paint_target = shell_glsl_effect_paint_target;
effect_class->pre_paint = shell_glsl_effect_pre_paint;
gobject_class->constructed = shell_glsl_effect_constructed; gobject_class->constructed = shell_glsl_effect_constructed;
gobject_class->dispose = shell_glsl_effect_dispose; gobject_class->dispose = shell_glsl_effect_dispose;
actor_class->get_paint_volume = shell_glsl_effect_get_paint_volume;
actor_class->paint = shell_glsl_effect_paint;
} }
/** /**

View File

@ -28,11 +28,11 @@ typedef enum {
#define SHELL_TYPE_GLSL_EFFECT (shell_glsl_effect_get_type ()) #define SHELL_TYPE_GLSL_EFFECT (shell_glsl_effect_get_type ())
G_DECLARE_DERIVABLE_TYPE (ShellGLSLEffect, shell_glsl_effect, G_DECLARE_DERIVABLE_TYPE (ShellGLSLEffect, shell_glsl_effect,
SHELL, GLSL_EFFECT, ClutterActor) SHELL, GLSL_EFFECT, ClutterOffscreenEffect)
struct _ShellGLSLEffectClass struct _ShellGLSLEffectClass
{ {
ClutterActorClass parent_class; ClutterOffscreenEffectClass parent_class;
CoglPipeline *base_pipeline; CoglPipeline *base_pipeline;