Commit f68e28b2 authored by Ell's avatar Ell

graph, process: replace DFS/BFS with topological search

Remove gegl_visitor_{dfs,bfs}_traverse().  They weren't actually
performing DFS and BFS, but were rather characterized by performing
topological (dependencies-first) and reverse-topological
(dependencies-last) search.

Instead, add gegl_visitor_traverse_[reverse_]topological(), which
perform a forward- and reverse-topological search, with lower
overhead (in the BFS case, the specific order is different than
before.)

Adapt the rest of the code to use the new functions.  In
particular, use a single GQueue in GeglGraphTraversal to store the
path in topological order, instead of separate DFS and BFS paths.
We forward-iterate over the path where we'd previously used the DFS
list, and reverse-iterate where we'd previously used the BFS list.

Remove GeglListVisitor, since it's no longer used.
parent ed2357d9
......@@ -262,8 +262,7 @@ gegl_dot_add_node_and_dependencies (GString *string,
string);
/* Add the nodes */
gegl_visitor_bfs_traverse (GEGL_VISITOR (dot_visitor),
GEGL_VISITABLE (node));
gegl_visitor_traverse (GEGL_VISITOR (dot_visitor), GEGL_VISITABLE (node));
/* Add the edges */
pad = gegl_node_get_pad (node, "output");
......@@ -285,8 +284,7 @@ gegl_dot_add_node_and_dependencies (GString *string,
}
gegl_visitor_bfs_traverse (GEGL_VISITOR (dot_visitor),
GEGL_VISITABLE (pad));
gegl_visitor_traverse (GEGL_VISITOR (dot_visitor), GEGL_VISITABLE (pad));
g_object_unref (dot_visitor);
}
......
......@@ -688,7 +688,7 @@ gegl_node_invalidated (GeglNode *node,
regions);
visitable = gegl_node_output_visitable_new (node);
gegl_visitor_bfs_traverse (visitor, visitable);
gegl_visitor_traverse_reverse_topological (visitor, visitable);
g_object_unref (visitable);
g_object_unref (visitor);
......@@ -771,7 +771,7 @@ gegl_node_invalidated (GeglNode *node,
rects);
visitable = gegl_node_output_visitable_new (node);
gegl_visitor_bfs_traverse (visitor, visitable);
gegl_visitor_traverse_reverse_topological (visitor, visitable);
g_object_unref (visitable);
g_object_unref (visitor);
......
......@@ -30,17 +30,18 @@
#include "gegl-visitable.h"
static void gegl_visitor_class_init (GeglVisitorClass *klass);
static void gegl_visitor_init (GeglVisitor *self);
static gboolean gegl_visitor_traverse_step (GeglVisitor *self,
GeglVisitable *visitable,
GHashTable *visited_set);
static gboolean gegl_visitor_dfs_traverse_step (GeglVisitor *self,
GeglVisitable *visitable,
GHashTable *visited_set);
static void gegl_visitor_bfs_init_step (GeglVisitor *self,
GeglVisitable *visitable,
GHashTable *edge_counts);
static void gegl_visitor_class_init (GeglVisitorClass *klass);
static void gegl_visitor_init (GeglVisitor *self);
static gboolean gegl_visitor_traverse_step (GeglVisitor *self,
GeglVisitable *visitable,
GHashTable *visited_set);
static gboolean gegl_visitor_traverse_topological_step (GeglVisitor *self,
GeglVisitable *visitable,
GHashTable *visited_set);
static void gegl_visitor_traverse_reverse_topological_step (GeglVisitor *self,
GeglVisitable *visitable,
GHashTable *visited_set,
GSList **stack);
G_DEFINE_TYPE (GeglVisitor, gegl_visitor, G_TYPE_OBJECT)
......@@ -99,9 +100,9 @@ gegl_visitor_visit_node (GeglVisitor *self,
* @self: #GeglVisitor
* @visitable: the start #GeglVisitable
*
* Traverse starting at @visitable in arbitrary order.
* Use this function when you don't need a DFS/BFS
* specifically, since it can be more efficient.
* Traverse in arbitrary order, starting at @visitable.
* Use this function when you don't need a specific
* traversal order, since it can be more efficient.
*
* Returns: %TRUE if traversal was terminated early.
**/
......@@ -117,7 +118,8 @@ gegl_visitor_traverse (GeglVisitor *self,
visited_set = g_hash_table_new (NULL, NULL);
result = gegl_visitor_traverse_step (self, visitable, visited_set);
result = gegl_visitor_traverse_step (self, visitable,
visited_set);
g_hash_table_unref (visited_set);
......@@ -143,7 +145,8 @@ gegl_visitor_traverse_step (GeglVisitor *self,
if (! g_hash_table_contains (visited_set, dependency))
{
if (gegl_visitor_traverse_step (self, dependency, visited_set))
if (gegl_visitor_traverse_step (self, dependency,
visited_set))
{
g_slist_free (dependencies);
......@@ -160,17 +163,18 @@ gegl_visitor_traverse_step (GeglVisitor *self,
}
/**
* gegl_visitor_dfs_traverse:
* gegl_visitor_traverse_topological:
* @self: #GeglVisitor
* @visitable: the start #GeglVisitable
*
* Traverse depth first starting at @visitable.
* Traverse in topological order (dependencies first),
* starting at @visitable.
*
* Returns: %TRUE if traversal was terminated early.
**/
gboolean
gegl_visitor_dfs_traverse (GeglVisitor *self,
GeglVisitable *visitable)
gegl_visitor_traverse_topological (GeglVisitor *self,
GeglVisitable *visitable)
{
GHashTable *visited_set;
gboolean result;
......@@ -180,7 +184,8 @@ gegl_visitor_dfs_traverse (GeglVisitor *self,
visited_set = g_hash_table_new (NULL, NULL);
result = gegl_visitor_dfs_traverse_step (self, visitable, visited_set);
result = gegl_visitor_traverse_topological_step (self, visitable,
visited_set);
g_hash_table_unref (visited_set);
......@@ -188,9 +193,9 @@ gegl_visitor_dfs_traverse (GeglVisitor *self,
}
static gboolean
gegl_visitor_dfs_traverse_step (GeglVisitor *self,
GeglVisitable *visitable,
GHashTable *visited_set)
gegl_visitor_traverse_topological_step (GeglVisitor *self,
GeglVisitable *visitable,
GHashTable *visited_set)
{
GSList *dependencies;
GSList *iter;
......@@ -203,7 +208,8 @@ gegl_visitor_dfs_traverse_step (GeglVisitor *self,
if (! g_hash_table_contains (visited_set, dependency))
{
if (gegl_visitor_dfs_traverse_step (self, dependency, visited_set))
if (gegl_visitor_traverse_topological_step (self, dependency,
visited_set))
{
g_slist_free (dependencies);
......@@ -223,75 +229,54 @@ gegl_visitor_dfs_traverse_step (GeglVisitor *self,
}
/**
* gegl_visitor_bfs_traverse:
* @self: a #GeglVisitor
* @visitable: the root #GeglVisitable.
* gegl_visitor_traverse_reverse_topological:
* @self: #GeglVisitor
* @visitable: the start #GeglVisitable
*
* Traverse breadth-first starting at @visitable.
* Traverse in reverse-topological order (dependencies
* last), starting at @visitable.
*
* Returns: %TRUE if traversal was terminated early.
**/
gboolean
gegl_visitor_bfs_traverse (GeglVisitor *self,
GeglVisitable *visitable)
gegl_visitor_traverse_reverse_topological (GeglVisitor *self,
GeglVisitable *visitable)
{
GHashTable *edge_counts;
GQueue queue = G_QUEUE_INIT;
GHashTable *visited_set;
GSList *stack = NULL;
g_return_val_if_fail (GEGL_IS_VISITOR (self), FALSE);
g_return_val_if_fail (GEGL_IS_VISITABLE (visitable), FALSE);
edge_counts = g_hash_table_new (NULL, NULL);
visited_set = g_hash_table_new (NULL, NULL);
gegl_visitor_bfs_init_step (self, visitable, edge_counts);
gegl_visitor_traverse_reverse_topological_step (self, visitable,
visited_set, &stack);
g_queue_push_tail (&queue, visitable);
g_hash_table_unref (visited_set);
while ((visitable = g_queue_pop_head (&queue)))
while (stack)
{
GSList *dependencies;
GSList *iter;
visitable = stack->data;
stack = g_slist_delete_link (stack, stack);
if (gegl_visitable_accept (visitable, self))
{
g_queue_clear (&queue);
g_hash_table_unref (edge_counts);
g_slist_free (stack);
return TRUE;
}
dependencies = gegl_visitable_depends_on (visitable);
for (iter = dependencies; iter; iter = g_slist_next (iter))
{
GeglVisitable *dependency = iter->data;
gint edges;
edges = GPOINTER_TO_INT (g_hash_table_lookup (edge_counts, dependency));
if (edges == 1)
{
g_queue_push_tail (&queue, dependency);
}
else
{
g_hash_table_insert (edge_counts,
dependency, GINT_TO_POINTER (edges - 1));
}
}
g_slist_free (dependencies);
}
g_hash_table_unref (edge_counts);
return FALSE;
}
static void
gegl_visitor_bfs_init_step (GeglVisitor *self,
GeglVisitable *visitable,
GHashTable *edge_counts)
gegl_visitor_traverse_reverse_topological_step (GeglVisitor *self,
GeglVisitable *visitable,
GHashTable *visited_set,
GSList **stack)
{
GSList *dependencies;
GSList *iter;
......@@ -301,15 +286,16 @@ gegl_visitor_bfs_init_step (GeglVisitor *self,
for (iter = dependencies; iter; iter = g_slist_next (iter))
{
GeglVisitable *dependency = iter->data;
gint edges;
edges = GPOINTER_TO_INT (g_hash_table_lookup (edge_counts, dependency));
g_hash_table_insert (edge_counts,
dependency, GINT_TO_POINTER (edges + 1));
if (edges == 0)
gegl_visitor_bfs_init_step (self, dependency, edge_counts);
if (! g_hash_table_contains (visited_set, dependency))
{
gegl_visitor_traverse_reverse_topological_step (self, dependency,
visited_set, stack);
}
}
g_slist_free (dependencies);
*stack = g_slist_prepend (*stack, visitable);
g_hash_table_add (visited_set, visitable);
}
......@@ -50,19 +50,19 @@ struct _GeglVisitorClass
};
GType gegl_visitor_get_type (void) G_GNUC_CONST;
gboolean gegl_visitor_visit_pad (GeglVisitor *self,
GeglPad *pad);
gboolean gegl_visitor_visit_node (GeglVisitor *self,
GeglNode *node);
gboolean gegl_visitor_traverse (GeglVisitor *self,
GeglVisitable *visitable);
gboolean gegl_visitor_dfs_traverse (GeglVisitor *self,
GeglVisitable *visitable);
gboolean gegl_visitor_bfs_traverse (GeglVisitor *self,
GeglVisitable *visitable);
GType gegl_visitor_get_type (void) G_GNUC_CONST;
gboolean gegl_visitor_visit_pad (GeglVisitor *self,
GeglPad *pad);
gboolean gegl_visitor_visit_node (GeglVisitor *self,
GeglNode *node);
gboolean gegl_visitor_traverse (GeglVisitor *self,
GeglVisitable *visitable);
gboolean gegl_visitor_traverse_topological (GeglVisitor *self,
GeglVisitable *visitable);
gboolean gegl_visitor_traverse_reverse_topological (GeglVisitor *self,
GeglVisitable *visitable);
G_END_DECLS
......
......@@ -27,14 +27,12 @@ libprocess_la_SOURCES = \
gegl-eval-manager.c \
gegl-graph-traversal.c \
gegl-graph-traversal-debug.c \
gegl-list-visitor.c \
gegl-processor.c \
\
gegl-eval-manager.h \
gegl-graph-debug.h \
gegl-graph-traversal.h \
gegl-graph-traversal-private.h \
gegl-list-visitor.h \
gegl-processor.h \
gegl-processor-private.h
......
......@@ -44,7 +44,9 @@ gegl_graph_dump_outputs (GeglNode *node)
gegl_graph_prepare (path);
for (list_iter = path->dfs_path; list_iter; list_iter = list_iter->next)
for (list_iter = g_queue_peek_head_link (&path->path);
list_iter;
list_iter = list_iter->next)
{
GeglNode *cur_node = GEGL_NODE (list_iter->data);
if (gegl_node_get_pad (cur_node, "output"))
......@@ -78,7 +80,9 @@ gegl_graph_dump_request (GeglNode *node,
gegl_graph_prepare (path);
gegl_graph_prepare_request (path, roi, 0);
for (list_iter = path->dfs_path; list_iter; list_iter = list_iter->next)
for (list_iter = g_queue_peek_head_link (&path->path);
list_iter;
list_iter = list_iter->next)
{
GeglNode *cur_node = GEGL_NODE (list_iter->data);
GeglOperationContext *context = g_hash_table_lookup (path->contexts, cur_node);
......
......@@ -22,9 +22,8 @@
struct _GeglGraphTraversal
{
GHashTable *contexts;
GList *dfs_path;
GList *bfs_path;
gboolean rects_dirty;
GQueue path;
gboolean rects_dirty;
GeglBuffer *shared_empty;
};
......
......@@ -30,12 +30,13 @@
#include "graph/gegl-node-private.h"
#include "graph/gegl-pad.h"
#include "graph/gegl-visitor.h"
#include "graph/gegl-callback-visitor.h"
#include "graph/gegl-visitable.h"
#include "graph/gegl-connection.h"
#include "process/gegl-graph-traversal.h"
#include "process/gegl-graph-traversal-private.h"
#include "process/gegl-list-visitor.h"
#include "operation/gegl-operation.h"
#include "operation/gegl-operation-context.h"
......@@ -54,11 +55,22 @@ static void _gegl_graph_do_build (GeglGraphTraversal *path
GeglNode *node);
static GeglBuffer *gegl_graph_get_shared_empty (GeglGraphTraversal *path);
static gboolean
_gegl_graph_do_build_add_node (GeglNode *node,
gpointer data)
{
GeglGraphTraversal *path = data;
g_queue_push_tail (&path->path, node);
return FALSE;
}
static void
_gegl_graph_do_build (GeglGraphTraversal *path, GeglNode *node)
{
GeglPad *pad = NULL;
GeglListVisitor *list_visitor = g_object_new (GEGL_TYPE_LIST_VISITOR, NULL);
GeglVisitor *visitor;
/* We need to check the real node of the output/input pad in case this is a proxy node */
pad = gegl_node_get_pad (node, "output");
......@@ -73,14 +85,17 @@ _gegl_graph_do_build (GeglGraphTraversal *path, GeglNode *node)
node = gegl_pad_get_node (pad);
}
path->dfs_path = gegl_list_visitor_get_dfs_path (list_visitor, GEGL_VISITABLE (node));
path->bfs_path = gegl_list_visitor_get_bfs_path (list_visitor, GEGL_VISITABLE (node));
visitor = gegl_callback_visitor_new (_gegl_graph_do_build_add_node, path);
gegl_visitor_traverse_topological (visitor, GEGL_VISITABLE (node));
g_object_unref (visitor);
path->contexts = g_hash_table_new_full (NULL,
NULL,
NULL,
(GDestroyNotify)gegl_operation_context_destroy);
path->rects_dirty = FALSE;
g_object_unref (list_visitor);
}
/**
......@@ -112,8 +127,7 @@ gegl_graph_build (GeglNode *node)
void
gegl_graph_rebuild (GeglGraphTraversal *path, GeglNode *node)
{
g_list_free (path->dfs_path);
g_list_free (path->bfs_path);
g_queue_clear (&path->path);
g_hash_table_unref (path->contexts);
/* Replaces everything but shared_empty */
......@@ -123,8 +137,7 @@ gegl_graph_rebuild (GeglGraphTraversal *path, GeglNode *node)
void
gegl_graph_free (GeglGraphTraversal *path)
{
g_list_free (path->dfs_path);
g_list_free (path->bfs_path);
g_queue_clear (&path->path);
g_hash_table_unref (path->contexts);
g_clear_object (&path->shared_empty);
g_free (path);
......@@ -143,7 +156,7 @@ gegl_graph_free (GeglGraphTraversal *path)
GeglRectangle
gegl_graph_get_bounding_box (GeglGraphTraversal *path)
{
GeglNode *node = GEGL_NODE (g_list_last (path->dfs_path)->data);
GeglNode *node = GEGL_NODE (g_queue_peek_tail (&path->path));
if (node->valid_have_rect)
{
return node->have_rect;
......@@ -162,7 +175,9 @@ gegl_graph_prepare (GeglGraphTraversal *path)
{
GList *list_iter = NULL;
for (list_iter = path->dfs_path; list_iter; list_iter = list_iter->next)
for (list_iter = g_queue_peek_head_link (&path->path);
list_iter;
list_iter = list_iter->next)
{
GeglNode *node = GEGL_NODE (list_iter->data);
GeglNode *parent;
......@@ -218,12 +233,14 @@ gegl_graph_prepare_request (GeglGraphTraversal *path,
GList *list_iter = NULL;
static const GeglRectangle empty_rect = {0, 0, 0, 0};
g_return_if_fail (path->bfs_path);
g_return_if_fail (! g_queue_is_empty (&path->path));
if (path->rects_dirty)
{
/* Zero all the needs rects so we can intersect with them below */
for (list_iter = path->bfs_path; list_iter; list_iter = list_iter->next)
for (list_iter = g_queue_peek_tail_link (&path->path);
list_iter;
list_iter = list_iter->prev)
{
GeglNode *node = GEGL_NODE (list_iter->data);
GeglOperationContext *context = g_hash_table_lookup (path->contexts, node);
......@@ -240,7 +257,7 @@ gegl_graph_prepare_request (GeglGraphTraversal *path,
{
/* Prep the first node */
GeglNode *node = GEGL_NODE (path->bfs_path->data);
GeglNode *node = GEGL_NODE (g_queue_peek_tail (&path->path));
GeglOperationContext *context = g_hash_table_lookup (path->contexts, node);
GeglRectangle new_need;
......@@ -253,7 +270,9 @@ gegl_graph_prepare_request (GeglGraphTraversal *path,
}
/* Iterate over all the nodes and propagate the requested rectangle */
for (list_iter = path->bfs_path; list_iter; list_iter = list_iter->next)
for (list_iter = g_queue_peek_tail_link (&path->path);
list_iter;
list_iter = list_iter->prev)
{
GeglNode *node = GEGL_NODE (list_iter->data);
GeglOperation *operation = node->operation;
......@@ -395,7 +414,9 @@ gegl_graph_process (GeglGraphTraversal *path,
GeglOperationContext *last_context = NULL;
GeglBuffer *operation_result = NULL;
for (list_iter = path->dfs_path; list_iter; list_iter = list_iter->next)
for (list_iter = g_queue_peek_head_link (&path->path);
list_iter;
list_iter = list_iter->next)
{
GeglNode *node = GEGL_NODE (list_iter->data);
GeglOperation *operation = node->operation;
......
/* This file is part of GEGL
*
* GEGL is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* GEGL is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with GEGL; if not, see <http://www.gnu.org/licenses/>.
*
* Copyright 2013 Daniel Sabo
*/
#include "config.h"
#include <glib-object.h>
#include <string.h>
#include "gegl.h"
#include "gegl-debug.h"
#include "gegl-types-internal.h"
#include "gegl-list-visitor.h"
#include "graph/gegl-node-private.h"
#include "graph/gegl-pad.h"
#include "graph/gegl-visitable.h"
#include "gegl-instrument.h"
#include "operation/gegl-operation.h"
static void gegl_list_visitor_class_init (GeglListVisitorClass *klass);
static gboolean gegl_list_visitor_visit_node (GeglVisitor *self,
GeglNode *node);
static void gegl_list_visitor_finalize (GObject *visitor);
G_DEFINE_TYPE (GeglListVisitor, gegl_list_visitor, GEGL_TYPE_VISITOR)
static void
gegl_list_visitor_class_init (GeglListVisitorClass *klass)
{
GeglVisitorClass *visitor_class = GEGL_VISITOR_CLASS (klass);
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
visitor_class->visit_node = gegl_list_visitor_visit_node;
gobject_class->finalize = gegl_list_visitor_finalize;
}
static void
gegl_list_visitor_init (GeglListVisitor *visitor)
{
GeglListVisitor *list_visitor = GEGL_LIST_VISITOR(visitor);
list_visitor->visit_path = NULL;
}
static void
gegl_list_visitor_finalize (GObject *object)
{
GeglListVisitor *list_visitor = GEGL_LIST_VISITOR(object);
if (list_visitor->visit_path)
{
g_list_free (list_visitor->visit_path);
list_visitor->visit_path = NULL;
}
G_OBJECT_CLASS (gegl_list_visitor_parent_class)->finalize (object);
}
void
gegl_list_visitor_reset (GeglListVisitor *self)
{
if (self->visit_path)
{
g_list_free (self->visit_path);
self->visit_path = NULL;
}
}
GList *
gegl_list_visitor_get_dfs_path (GeglListVisitor *self,
GeglVisitable *visitable)
{
GList *result;
gegl_list_visitor_reset (self);
gegl_visitor_dfs_traverse (GEGL_VISITOR (self), visitable);
result = self->visit_path;
self->visit_path = NULL;
return g_list_reverse (result);
}
GList *
gegl_list_visitor_get_bfs_path (GeglListVisitor *self,
GeglVisitable *visitable)
{
GList *result;
gegl_list_visitor_reset (self);
gegl_visitor_bfs_traverse (GEGL_VISITOR (self), visitable);
result = self->visit_path;
self->visit_path = NULL;
return g_list_reverse (result);
}
static gboolean
gegl_list_visitor_visit_node (GeglVisitor *visitor,
GeglNode *node)
{
GeglListVisitor *list_visitor = GEGL_LIST_VISITOR(visitor);
list_visitor->visit_path = g_list_prepend (list_visitor->visit_path, node);
return FALSE;
}
/* This file is part of GEGL
*
* GEGL is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* GEGL is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with GEGL; if not, see <http://www.gnu.org/licenses/>.
*
* Copyright 2013 Daniel Sabo
*/
#ifndef __GEGL_LIST_VISITOR_H__
#define __GEGL_LIST_VISITOR_H__
#include "graph/gegl-visitor.h"
G_BEGIN_DECLS
#define GEGL_TYPE_LIST_VISITOR (gegl_list_visitor_get_type ())
#define GEGL_LIST_VISITOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GEGL_TYPE_LIST_VISITOR, GeglListVisitor))
#define GEGL_LIST_VISITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GEGL_TYPE_LIST_VISITOR, GeglListVisitorClass))
#define GEGL_IS_LIST_VISITOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GEGL_TYPE_LIST_VISITOR))
#define GEGL_IS_LIST_VISITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GEGL_TYPE_LIST_VISITOR))
#define GEGL_LIST_VISITOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GEGL_TYPE_LIST_VISITOR, GeglListVisitorClass))
typedef struct _GeglListVisitorClass GeglListVisitorClass;
typedef struct _GeglListVisitor GeglListVisitor;
struct _GeglListVisitor
{
GeglVisitor parent_instance;
GList *visit_path;
};
struct _GeglListVisitorClass
{
GeglVisitorClass parent_class;
};
GType gegl_list_visitor_get_type (void) G_GNUC_CONST;
void gegl_list_visitor_reset (GeglListVisitor *self);
GList *gegl_list_visitor_get_dfs_path (GeglListVisitor *self,
GeglVisitable *visitable);
GList *gegl_list_visitor_get_bfs_path (GeglListVisitor *self,
GeglVisitable *visitable);
G_END_DECLS
#endif /* __GEGL_LIST_VISITOR_H__ */
......@@ -36,8 +36,8 @@
#include "gegl-processor-private.h"
#include "graph/gegl-visitor.h"
#include "graph/gegl-callback-visitor.h"
#include "graph/gegl-visitable.h"
#include "process/gegl-list-visitor.h"
#include "opencl/gegl-cl.h"
......@@ -760,6 +760,14 @@ gegl_processor_render (GeglProcessor *processor,
return !gegl_processor_is_rendered (processor);
}
static gboolean
gegl_processor_work_is_opencl_node (GeglNode *node,
gpointer data)
{
return GEGL_OPERATION_GET_CLASS (node->operation)->cl_data ||
GEGL_OPERATION_GET_CLASS (node->operation)->opencl_support;
}
/* Will call gegl_processor_render and when there is no more work to be done,
* it will write the result to the destination */
gboolean
......@@ -773,23 +781,14 @@ gegl_processor_work (GeglProcessor *processor,
if (gegl_cl_is_accelerated ()
&& processor->chunk_size != GEGL_CL_CHUNK_SIZE)
{
GeglListVisitor *visitor = g_object_new (GEGL_TYPE_LIST_VISITOR, NULL);
GList *iterator = NULL;
GList *visits_list = NULL;
visits_list = gegl_list_visitor_get_dfs_path (visitor, GEGL_VISITABLE (processor->real_node));
GeglVisitor *visitor;
for (iterator = visits_list; iterator; iterator = iterator->next)
{
GeglNode *node = (GeglNode*) iterator->data;
if (GEGL_OPERATION_GET_CLASS(node->operation)->cl_data
|| GEGL_OPERATION_GET_CLASS(node->operation)->opencl_support)
{
processor->chunk_size = GEGL_CL_CHUNK_SIZE;
break;
}
}
visitor = gegl_callback_visitor_new (gegl_processor_work_is_opencl_node,
NULL);
if (gegl_visitor_traverse (visitor, GEGL_VISITABLE (processor->real_node)))
processor->chunk_size = GEGL_CL_CHUNK_SIZE;