Commit e02cb6ad authored by Ell's avatar Ell

app: exclude invisible filters from filter-stack graph

Currently, when a GimpFilter's visibility changes, we rely on its
various visibility-changed signal handlers to rewire the filter
node's graph to reflect the change.  This has two main
disadvantages:

  - There's no easy, generic way to toggle a filter's  effect,
    especially one that is not subclassed, since GimpFilter only
    takes care of the case where visibility becomes FALSE, and does
    nothing by itself when it becomes TRUE again.

  - While GimpDrawable does handle the visibility => TRUE case, it
    doesn't disconnect the filter's input from its mode and
    (potentially) source nodes when it becomes invisible.  As a
    result, while none of the drawable's graph is processed as part
    of the composition when not visible, the mode and source nodes
    do get invalidated when the filter's input is invalidated, such
    as while painting on a layer below the drawable.  This is
    particularly bad for pass-through groups, since their source
    node can be an arbitrarily complex graph, whose invlidation
    incurs a nontrivial overhead.

Instead, don't touch the filter's node at all when visibility
changes, and rather have GimpFilterStack remove it from the graph
entirely when the filter becomes invisible, and re-add it once it
becomes visible again.  This solves both of the above problems, as
well as simplifies the code.
parent 73d7a81a
......@@ -91,7 +91,6 @@ static gboolean gimp_drawable_get_size (GimpViewable *viewable,
gint *width,
gint *height);
static void gimp_drawable_visibility_changed (GimpFilter *filter);
static GeglNode * gimp_drawable_get_node (GimpFilter *filter);
static void gimp_drawable_removed (GimpItem *item);
......@@ -226,42 +225,41 @@ gimp_drawable_class_init (GimpDrawableClass *klass)
gimp_marshal_VOID__VOID,
G_TYPE_NONE, 0);
object_class->dispose = gimp_drawable_dispose;
object_class->finalize = gimp_drawable_finalize;
object_class->set_property = gimp_drawable_set_property;
object_class->get_property = gimp_drawable_get_property;
gimp_object_class->get_memsize = gimp_drawable_get_memsize;
viewable_class->get_size = gimp_drawable_get_size;
viewable_class->get_new_preview = gimp_drawable_get_new_preview;
viewable_class->get_new_pixbuf = gimp_drawable_get_new_pixbuf;
filter_class->visibility_changed = gimp_drawable_visibility_changed;
filter_class->get_node = gimp_drawable_get_node;
item_class->removed = gimp_drawable_removed;
item_class->duplicate = gimp_drawable_duplicate;
item_class->scale = gimp_drawable_scale;
item_class->resize = gimp_drawable_resize;
item_class->flip = gimp_drawable_flip;
item_class->rotate = gimp_drawable_rotate;
item_class->transform = gimp_drawable_transform;
klass->update = gimp_drawable_real_update;
klass->alpha_changed = NULL;
klass->estimate_memsize = gimp_drawable_real_estimate_memsize;
klass->invalidate_boundary = NULL;
klass->get_active_components = NULL;
klass->get_active_mask = NULL;
klass->convert_type = gimp_drawable_real_convert_type;
klass->apply_buffer = gimp_drawable_real_apply_buffer;
klass->replace_buffer = gimp_drawable_real_replace_buffer;
klass->get_buffer = gimp_drawable_real_get_buffer;
klass->set_buffer = gimp_drawable_real_set_buffer;
klass->push_undo = gimp_drawable_real_push_undo;
klass->swap_pixels = gimp_drawable_real_swap_pixels;
klass->get_source_node = gimp_drawable_real_get_source_node;
object_class->dispose = gimp_drawable_dispose;
object_class->finalize = gimp_drawable_finalize;
object_class->set_property = gimp_drawable_set_property;
object_class->get_property = gimp_drawable_get_property;
gimp_object_class->get_memsize = gimp_drawable_get_memsize;
viewable_class->get_size = gimp_drawable_get_size;
viewable_class->get_new_preview = gimp_drawable_get_new_preview;
viewable_class->get_new_pixbuf = gimp_drawable_get_new_pixbuf;
filter_class->get_node = gimp_drawable_get_node;
item_class->removed = gimp_drawable_removed;
item_class->duplicate = gimp_drawable_duplicate;
item_class->scale = gimp_drawable_scale;
item_class->resize = gimp_drawable_resize;
item_class->flip = gimp_drawable_flip;
item_class->rotate = gimp_drawable_rotate;
item_class->transform = gimp_drawable_transform;
klass->update = gimp_drawable_real_update;
klass->alpha_changed = NULL;
klass->estimate_memsize = gimp_drawable_real_estimate_memsize;
klass->invalidate_boundary = NULL;
klass->get_active_components = NULL;
klass->get_active_mask = NULL;
klass->convert_type = gimp_drawable_real_convert_type;
klass->apply_buffer = gimp_drawable_real_apply_buffer;
klass->replace_buffer = gimp_drawable_real_replace_buffer;
klass->get_buffer = gimp_drawable_real_get_buffer;
klass->set_buffer = gimp_drawable_real_set_buffer;
klass->push_undo = gimp_drawable_real_push_undo;
klass->swap_pixels = gimp_drawable_real_swap_pixels;
klass->get_source_node = gimp_drawable_real_get_source_node;
g_object_class_override_property (object_class, PROP_BUFFER, "buffer");
......@@ -387,35 +385,6 @@ gimp_drawable_get_size (GimpViewable *viewable,
return TRUE;
}
static void
gimp_drawable_visibility_changed (GimpFilter *filter)
{
GimpDrawable *drawable = GIMP_DRAWABLE (filter);
GeglNode *node;
/* don't use gimp_filter_get_node() because that would create
* the node.
*/
node = gimp_filter_peek_node (filter);
if (node)
{
GeglNode *output = gegl_node_get_output_proxy (node, "output");
if (gimp_filter_get_visible (filter))
{
gegl_node_connect_to (drawable->private->mode_node, "output",
output, "input");
}
else
{
/* Handled by GimpFilter */
}
}
GIMP_FILTER_CLASS (parent_class)->visibility_changed (filter);
}
static GeglNode *
gimp_drawable_get_node (GimpFilter *filter)
{
......@@ -438,16 +407,8 @@ gimp_drawable_get_node (GimpFilter *filter)
gegl_node_connect_to (input, "output",
drawable->private->mode_node, "input");
if (gimp_filter_get_visible (filter))
{
gegl_node_connect_to (drawable->private->mode_node, "output",
output, "input");
}
else
{
/* Handled by GimpFilter */
}
gegl_node_connect_to (drawable->private->mode_node, "output",
output, "input");
return node;
}
......
......@@ -63,21 +63,20 @@ struct _GimpFilterPrivate
/* local function prototypes */
static void gimp_filter_finalize (GObject *object);
static void gimp_filter_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec);
static void gimp_filter_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec);
static void gimp_filter_finalize (GObject *object);
static void gimp_filter_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec);
static void gimp_filter_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec);
static gint64 gimp_filter_get_memsize (GimpObject *object,
gint64 *gui_size);
static gint64 gimp_filter_get_memsize (GimpObject *object,
gint64 *gui_size);
static void gimp_filter_real_visibility_changed (GimpFilter *filter);
static GeglNode * gimp_filter_real_get_node (GimpFilter *filter);
static GeglNode * gimp_filter_real_get_node (GimpFilter *filter);
G_DEFINE_TYPE (GimpFilter, gimp_filter, GIMP_TYPE_VIEWABLE)
......@@ -108,7 +107,7 @@ gimp_filter_class_init (GimpFilterClass *klass)
gimp_object_class->get_memsize = gimp_filter_get_memsize;
klass->visibility_changed = gimp_filter_real_visibility_changed;
klass->visibility_changed = NULL;
klass->get_node = gimp_filter_real_get_node;
g_object_class_install_property (object_class, PROP_VISIBLE,
......@@ -202,28 +201,6 @@ gimp_filter_get_memsize (GimpObject *object,
gui_size);
}
static void
gimp_filter_real_visibility_changed (GimpFilter *filter)
{
GeglNode *node = gimp_filter_peek_node (filter);
if (node)
{
if (gimp_filter_get_visible (filter))
{
/* Leave this up to subclasses */
}
else
{
GeglNode *input = gegl_node_get_input_proxy (node, "input");
GeglNode *output = gegl_node_get_output_proxy (node, "output");
gegl_node_connect_to (input, "output",
output, "input");
}
}
}
static GeglNode *
gimp_filter_real_get_node (GimpFilter *filter)
{
......@@ -231,19 +208,6 @@ gimp_filter_real_get_node (GimpFilter *filter)
private->node = gegl_node_new ();
if (gimp_filter_get_visible (filter))
{
/* Leave this up to subclasses */
}
else
{
GeglNode *input = gegl_node_get_input_proxy (private->node, "input");
GeglNode *output = gegl_node_get_output_proxy (private->node, "output");
gegl_node_connect_to (input, "output",
output, "input");
}
return private->node;
}
......
......@@ -110,13 +110,16 @@ gimp_filter_stack_add (GimpContainer *container,
GIMP_CONTAINER_CLASS (parent_class)->add (container, object);
if (stack->graph)
if (gimp_filter_get_visible (filter))
{
gegl_node_add_child (stack->graph, gimp_filter_get_node (filter));
gimp_filter_stack_add_node (stack, filter);
}
if (stack->graph)
{
gegl_node_add_child (stack->graph, gimp_filter_get_node (filter));
gimp_filter_stack_add_node (stack, filter);
}
gimp_filter_stack_update_last_node (stack);
gimp_filter_stack_update_last_node (stack);
}
}
static void
......@@ -126,7 +129,7 @@ gimp_filter_stack_remove (GimpContainer *container,
GimpFilterStack *stack = GIMP_FILTER_STACK (container);
GimpFilter *filter = GIMP_FILTER (object);
if (stack->graph)
if (stack->graph && gimp_filter_get_visible (filter))
{
gimp_filter_stack_remove_node (stack, filter);
gegl_node_remove_child (stack->graph, gimp_filter_get_node (filter));
......@@ -134,8 +137,11 @@ gimp_filter_stack_remove (GimpContainer *container,
GIMP_CONTAINER_CLASS (parent_class)->remove (container, object);
gimp_filter_set_is_last_node (filter, FALSE);
gimp_filter_stack_update_last_node (stack);
if (gimp_filter_get_visible (filter))
{
gimp_filter_set_is_last_node (filter, FALSE);
gimp_filter_stack_update_last_node (stack);
}
}
static void
......@@ -146,15 +152,18 @@ gimp_filter_stack_reorder (GimpContainer *container,
GimpFilterStack *stack = GIMP_FILTER_STACK (container);
GimpFilter *filter = GIMP_FILTER (object);
if (stack->graph)
if (stack->graph && gimp_filter_get_visible (filter))
gimp_filter_stack_remove_node (stack, filter);
GIMP_CONTAINER_CLASS (parent_class)->reorder (container, object, new_index);
gimp_filter_stack_update_last_node (stack);
if (gimp_filter_get_visible (filter))
{
gimp_filter_stack_update_last_node (stack);
if (stack->graph)
gimp_filter_stack_add_node (stack, filter);
if (stack->graph)
gimp_filter_stack_add_node (stack, filter);
}
}
......@@ -176,9 +185,7 @@ GeglNode *
gimp_filter_stack_get_graph (GimpFilterStack *stack)
{
GList *list;
GeglNode *first = NULL;
GeglNode *previous = NULL;
GeglNode *input;
GeglNode *previous;
GeglNode *output;
g_return_val_if_fail (GIMP_IS_FILTER_STACK (stack), NULL);
......@@ -188,40 +195,32 @@ gimp_filter_stack_get_graph (GimpFilterStack *stack)
stack->graph = gegl_node_new ();
previous = gegl_node_get_input_proxy (stack->graph, "input");
for (list = GIMP_LIST (stack)->queue->tail;
list;
list = g_list_previous (list))
{
GimpFilter *filter = list->data;
GeglNode *node = gimp_filter_get_node (filter);
GeglNode *node;
if (! first)
first = node;
if (! gimp_filter_get_visible (filter))
continue;
node = gimp_filter_get_node (filter);
gegl_node_add_child (stack->graph, node);
if (previous)
gegl_node_connect_to (previous, "output",
node, "input");
gegl_node_connect_to (previous, "output",
node, "input");
previous = node;
}
input = gegl_node_get_input_proxy (stack->graph, "input");
output = gegl_node_get_output_proxy (stack->graph, "output");
if (first && previous)
{
gegl_node_connect_to (input, "output",
first, "input");
gegl_node_connect_to (previous, "output",
output, "input");
}
else
{
gegl_node_connect_to (input, "output",
output, "input");
}
gegl_node_connect_to (previous, "output",
output, "input");
return stack->graph;
}
......@@ -233,88 +232,70 @@ static void
gimp_filter_stack_add_node (GimpFilterStack *stack,
GimpFilter *filter)
{
GimpFilter *filter_below;
GeglNode *node_above;
GeglNode *node_below;
GeglNode *node;
gint index;
GeglNode *node;
GeglNode *node_above = NULL;
GeglNode *node_below = NULL;
GList *iter;
node = gimp_filter_get_node (filter);
index = gimp_container_get_child_index (GIMP_CONTAINER (stack),
GIMP_OBJECT (filter));
if (index == 0)
{
node_above = gegl_node_get_output_proxy (stack->graph, "output");
}
else
iter = g_list_find (GIMP_LIST (stack)->queue->head, filter);
while ((iter = g_list_previous (iter)))
{
GimpFilter *filter_above = (GimpFilter *)
gimp_container_get_child_by_index (GIMP_CONTAINER (stack), index - 1);
GimpFilter *filter_above = iter->data;
node_above = gimp_filter_get_node (filter_above);
}
if (gimp_filter_get_visible (filter_above))
{
node_above = gimp_filter_get_node (filter_above);
gegl_node_connect_to (node, "output",
node_above, "input");
break;
}
}
filter_below = (GimpFilter *)
gimp_container_get_child_by_index (GIMP_CONTAINER (stack), index + 1);
if (! node_above)
node_above = gegl_node_get_output_proxy (stack->graph, "output");
if (filter_below)
{
node_below = gimp_filter_get_node (filter_below);
}
else
{
node_below = gegl_node_get_input_proxy (stack->graph, "input");
}
node_below = gegl_node_get_producer (node_above, "input", NULL);
gegl_node_connect_to (node_below, "output",
node, "input");
gegl_node_connect_to (node, "output",
node_above, "input");
}
static void
gimp_filter_stack_remove_node (GimpFilterStack *stack,
GimpFilter *filter)
{
GimpFilter *filter_below;
GeglNode *node_above;
GeglNode *node_below;
GeglNode *node;
gint index;
GeglNode *node;
GeglNode *node_above = NULL;
GeglNode *node_below = NULL;
GList *iter;
node = gimp_filter_get_node (filter);
gegl_node_disconnect (node, "input");
iter = g_list_find (GIMP_LIST (stack)->queue->head, filter);
index = gimp_container_get_child_index (GIMP_CONTAINER (stack),
GIMP_OBJECT (filter));
if (index == 0)
{
node_above = gegl_node_get_output_proxy (stack->graph, "output");
}
else
while ((iter = g_list_previous (iter)))
{
GimpFilter *filter_above = (GimpFilter *)
gimp_container_get_child_by_index (GIMP_CONTAINER (stack), index - 1);
GimpFilter *filter_above = iter->data;
node_above = gimp_filter_get_node (filter_above);
if (gimp_filter_get_visible (filter_above))
{
node_above = gimp_filter_get_node (filter_above);
break;
}
}
filter_below = (GimpFilter *)
gimp_container_get_child_by_index (GIMP_CONTAINER (stack), index + 1);
if (! node_above)
node_above = gegl_node_get_output_proxy (stack->graph, "output");
if (filter_below)
{
node_below = gimp_filter_get_node (filter_below);
}
else
{
node_below = gegl_node_get_input_proxy (stack->graph, "input");
}
node_below = gegl_node_get_producer (node, "input", NULL);
gegl_node_disconnect (node, "input");
gegl_node_connect_to (node_below, "output",
node_above, "input");
......@@ -348,5 +329,22 @@ static void
gimp_filter_stack_filter_visible (GimpFilter *filter,
GimpFilterStack *stack)
{
if (stack->graph)
{
if (gimp_filter_get_visible (filter))
{
gegl_node_add_child (stack->graph, gimp_filter_get_node (filter));
gimp_filter_stack_add_node (stack, filter);
}
else
{
gimp_filter_stack_remove_node (stack, filter);
gegl_node_remove_child (stack->graph, gimp_filter_get_node (filter));
}
}
gimp_filter_stack_update_last_node (stack);
if (! gimp_filter_get_visible (filter))
gimp_filter_set_is_last_node (filter, FALSE);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment