[gegl/newgraph-merge: 8/8] New graph processor
- From: Daniel Sabo <daniels src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gegl/newgraph-merge: 8/8] New graph processor
- Date: Tue, 4 Jun 2013 06:43:38 +0000 (UTC)
commit ffd9c488e6e83aaa8d01cabcbc5e82c2ee816b49
Author: Daniel Sabo <DanielSabo gmail com>
Date: Mon Jun 3 23:14:08 2013 -0700
New graph processor
Streamline the graph evaluation process to reduce overhead.
Important changes / gotchas:
* get_cached_region is no longer used. The cache bounds are
always the full output bounds, but the request will not be
expanded.
* The cache intersect is calculated after all requests to a node
are combined, so partial cache hits from multiple nodes may
skip the cache.
* Meta nodes (nodes who's pads do not reference them) will never
be visited.
* Prepare is called only once per node, and must not modify the
connectivity of the graph.
gegl/gegl-apply.c | 3 -
gegl/gegl.h | 12 +
gegl/graph/Makefile.am | 2 +-
gegl/graph/gegl-node.c | 293 ++++--------------
gegl/graph/gegl-node.h | 4 +
gegl/graph/gegl-visitor.c | 104 +------
gegl/graph/gegl-visitor.h | 3 -
gegl/operation/gegl-operation-context.c | 14 +-
gegl/operation/gegl-operation-context.h | 4 +-
gegl/operation/gegl-operation.c | 2 +
gegl/process/Makefile.am | 23 +-
gegl/process/gegl-debug-rect-visitor.c | 79 -----
gegl/process/gegl-debug-rect-visitor.h | 53 ---
gegl/process/gegl-eval-manager.c | 225 ++++----------
gegl/process/gegl-eval-manager.h | 35 +--
gegl/process/gegl-eval-visitor.c | 220 -------------
gegl/process/gegl-eval-visitor.h | 55 ----
gegl/process/gegl-finish-visitor.c | 61 ----
gegl/process/gegl-finish-visitor.h | 53 ---
gegl/process/gegl-graph-debug.h | 25 ++
gegl/process/gegl-graph-traversal-debug.c | 95 ++++++
gegl/process/gegl-graph-traversal-private.h | 31 ++
gegl/process/gegl-graph-traversal.c | 453 +++++++++++++++++++++++++++
gegl/process/gegl-graph-traversal.h | 17 +
gegl/process/gegl-have-visitor.c | 85 -----
gegl/process/gegl-have-visitor.h | 53 ---
gegl/process/gegl-list-visitor.c | 120 +++++++
gegl/process/gegl-list-visitor.h | 60 ++++
gegl/process/gegl-need-visitor.c | 82 -----
gegl/process/gegl-need-visitor.h | 53 ---
gegl/process/gegl-prepare-visitor.c | 104 ------
gegl/process/gegl-prepare-visitor.h | 53 ---
gegl/process/gegl-processor.c | 27 +-
33 files changed, 993 insertions(+), 1510 deletions(-)
---
diff --git a/gegl/gegl-apply.c b/gegl/gegl-apply.c
index 3cb7f2d..a5b1bb2 100644
--- a/gegl/gegl-apply.c
+++ b/gegl/gegl-apply.c
@@ -37,9 +37,6 @@
#include "operation/gegl-operation-point-filter.h"
#include "process/gegl-eval-manager.h"
-#include "process/gegl-have-visitor.h"
-#include "process/gegl-prepare-visitor.h"
-#include "process/gegl-finish-visitor.h"
#include "process/gegl-processor.h"
diff --git a/gegl/gegl.h b/gegl/gegl.h
index 4fa6e11..40ffecc 100644
--- a/gegl/gegl.h
+++ b/gegl/gegl.h
@@ -421,6 +421,18 @@ void gegl_node_blit (GeglNode *node,
GeglBlitFlags flags);
/**
+ * gegl_node_blit_buffer:
+ * @node: a #GeglNode
+ * @buffer: (transfer none) (allow-none): the #GeglBuffer to render to.
+ * @roi: (allow-none): the rectangle to render.
+ *
+ * Render a rectangular region from a node to the given buffer.
+ */
+void gegl_node_blit_buffer (GeglNode *node,
+ GeglBuffer *buffer,
+ const GeglRectangle *roi);
+
+/**
* gegl_node_process:
* @sink_node: a #GeglNode without outputs.
*
diff --git a/gegl/graph/Makefile.am b/gegl/graph/Makefile.am
index a66702b..b72e24c 100644
--- a/gegl/graph/Makefile.am
+++ b/gegl/graph/Makefile.am
@@ -13,7 +13,7 @@ AM_CFLAGS = $(DEP_CFLAGS) $(BABL_CFLAGS)
noinst_LTLIBRARIES = libgraph.la
-#libgraph_publicdir = $(includedir)/gegl-$(GEGL_API_VERSION)/gegl/graph
+#libgraph_publicdir = $(includedir)/gegl-$(GEGL_API_VERSION)/graph
#libgraph_public_HEADERS = #
libgraph_la_SOURCES = \
diff --git a/gegl/graph/gegl-node.c b/gegl/graph/gegl-node.c
index 4285f2f..1e75f81 100644
--- a/gegl/graph/gegl-node.c
+++ b/gegl/graph/gegl-node.c
@@ -15,6 +15,7 @@
*
* Copyright 2003 Calvin Williamson
* 2006 Øyvind Kolås
+ * 2013 Daniel Sabo
*/
#include "config.h"
@@ -35,14 +36,13 @@
#include "gegl-visitable.h"
#include "gegl-config.h"
+#include "graph/gegl-visitor.h"
+
#include "operation/gegl-operation.h"
#include "operation/gegl-operations.h"
#include "operation/gegl-operation-meta.h"
#include "process/gegl-eval-manager.h"
-#include "process/gegl-have-visitor.h"
-#include "process/gegl-prepare-visitor.h"
-#include "process/gegl-finish-visitor.h"
#include "process/gegl-processor.h"
enum
@@ -71,7 +71,7 @@ struct _GeglNodePrivate
gchar *name;
GeglProcessor *processor;
GHashTable *contexts;
- GeglEvalManager *eval_manager[GEGL_MAX_THREADS];
+ GeglEvalManager *eval_manager;
};
@@ -232,15 +232,11 @@ gegl_node_dispose (GObject *gobject)
self->cache = NULL;
}
- {
- gint i;
- for (i=0; i<GEGL_MAX_THREADS; i++)
- if (self->priv->eval_manager[i])
- {
- g_object_unref (self->priv->eval_manager[i]);
- self->priv->eval_manager[i] = NULL;
- }
- }
+ if (self->priv->eval_manager)
+ {
+ g_object_unref (self->priv->eval_manager);
+ self->priv->eval_manager = NULL;
+ }
if (self->priv->processor)
{
@@ -864,92 +860,59 @@ gegl_node_link_many (GeglNode *source,
va_end (var_args);
}
-static void gegl_node_ensure_eval_manager (GeglNode *self,
- const gchar *pad,
- gint no)
+static GeglEvalManager *
+gegl_node_get_eval_manager (GeglNode *self)
{
- if (!self->priv->eval_manager[no])
- self->priv->eval_manager[no] = gegl_eval_manager_new (self, pad);
+ if (!self->priv->eval_manager)
+ self->priv->eval_manager = gegl_eval_manager_new (self, "output");
+ return self->priv->eval_manager;
}
-/* Will set the eval_manager's roi to the supplied roi if defined, otherwise
- * it will use the node's bounding box. Then the gegl_eval_manager_apply will
- * be called.
- */
static GeglBuffer *
gegl_node_apply_roi (GeglNode *self,
- const gchar *output_pad_name,
- const GeglRectangle *roi,
- gint tid)
-{
- /* This is a potential spot to multiplex paralell processing,
- * doing so, might cause a lot of tile overlap between
- * processes if were not careful (wouldn't neccesarily be totally
- * bad if that happens though.
- */
- GeglBuffer *buffer;
-
- /*g_print ("%i %i %i %i %i\n", tid, roi->x, roi->y, roi->width, roi->height);*/
+ const GeglRectangle *roi)
+{
+ GeglEvalManager *eval_manager = gegl_node_get_eval_manager (self);
if (roi)
{
- self->priv->eval_manager[tid]->roi = *roi;
+ return gegl_eval_manager_apply (eval_manager, roi);
}
else
{
- self->priv->eval_manager[tid]->roi = gegl_node_get_bounding_box (self);
+ GeglRectangle node_bbox = gegl_node_get_bounding_box (self);
+ return gegl_eval_manager_apply (eval_manager, &node_bbox);
}
- buffer = gegl_eval_manager_apply (self->priv->eval_manager[tid]);
- return buffer;
}
-
-typedef struct ThreadData
+void
+gegl_node_blit_buffer (GeglNode *self,
+ GeglBuffer *buffer,
+ const GeglRectangle *roi)
{
- GeglNode *node;
- gint tid;
- GeglRectangle roi;
- const gchar *pad;
+ GeglEvalManager *eval_manager;
+ GeglBuffer *result;
+ GeglRectangle request;
- const Babl *format;
- gpointer destination_buf;
- gint rowstride;
- GeglBlitFlags flags;
-} ThreadData;
+ eval_manager = gegl_node_get_eval_manager (self);
-static GThreadPool *pool = NULL;
-static GMutex mutex = { 0, };
-static GCond cond = { 0, };
-static gint remaining_tasks = 0;
-
-static void spawnrender (gpointer data,
- gpointer foo)
-{
- ThreadData *td = data;
- GeglBuffer * buffer;
- buffer = gegl_node_apply_roi (td->node, td->pad, &td->roi, td->tid);
-
- if ((buffer ) && td->destination_buf)
- {
- gegl_buffer_get (buffer, &td->roi, 1.0, td->format, td->destination_buf, td->rowstride,
- GEGL_ABYSS_NONE);
- }
+ if (roi)
+ request = *roi;
+ else if (buffer)
+ request = *gegl_buffer_get_extent (buffer);
+ else
+ request = gegl_node_get_bounding_box (self);
- /* and unrefing to ultimately clean it off from the graph */
- if (buffer)
- g_object_unref (buffer);
+ result = gegl_eval_manager_apply (eval_manager, &request);
- g_mutex_lock (&mutex);
- remaining_tasks --;
- if (remaining_tasks == 0)
+ if (result)
{
- /* we were the last task, we're not busy rendering any more */
- g_cond_signal (&cond);
+ if (buffer)
+ gegl_buffer_copy (result, &request, buffer, NULL);
+ g_object_unref (result);
}
- g_mutex_unlock (&mutex);
}
-
void
gegl_node_blit (GeglNode *self,
gdouble scale,
@@ -959,124 +922,30 @@ gegl_node_blit (GeglNode *self,
gint rowstride,
GeglBlitFlags flags)
{
- gint threads;
g_return_if_fail (GEGL_IS_NODE (self));
g_return_if_fail (roi != NULL);
- threads = gegl_config ()->threads;
- if (threads > GEGL_MAX_THREADS)
- threads = 1;
-
- if (pool == NULL)
- {
- pool = g_thread_pool_new (spawnrender, NULL, threads, TRUE, NULL);
- g_mutex_init (&mutex);
- g_cond_init (&cond);
- }
-
if (flags == GEGL_BLIT_DEFAULT)
-#if 1 /* multi threaded version */
- {
- ThreadData data[GEGL_MAX_THREADS];
- gint i;
-
- /* Subdivide along the largest of width/height, this should be further
- * extended similar to the subdivizion done in GeglProcessor, to get as
- * square as possible subregions.
- */
- gboolean horizontal = roi->width > roi->height;
-
- gint rowskip = 0;
-
- if (!format)
- format = babl_format ("RGBA float"); /* XXX: This probably duplicates
- another hardcoded format, they
- should be turned into a
- constant. */
- if (horizontal)
- rowskip = (roi->width/threads) * babl_format_get_bytes_per_pixel (format);
-
- if (rowstride == GEGL_AUTO_ROWSTRIDE)
- rowstride = roi->width * babl_format_get_bytes_per_pixel (format);
-
- data[0].node = self;
- data[0].pad = "output";
- data[0].format = format;
- data[0].destination_buf = destination_buf;
- data[0].rowstride = rowstride;
- data[0].flags = flags;
-
- for (i=0;i<threads;i++)
- {
- data[i] = data[0];
- data[i].roi = *roi;
- gegl_node_ensure_eval_manager (self, "output", i);
- if (horizontal)
- {
- data[i].roi.width = roi->width / threads;
- data[i].roi.x = roi->x + roi->width/threads * i;
- }
- else
- {
- data[i].roi.height = roi->height / threads;
- data[i].roi.y = roi->y + roi->height/threads * i;
- }
-
- data[i].tid = i;
- if (horizontal)
- data[i].destination_buf = ((gchar*)destination_buf + rowskip * i);
- else
- data[i].destination_buf = ((gchar*)destination_buf + rowstride * (roi->height/threads) * i);
- }
- if (horizontal)
- data[threads-1].roi.width = roi->width - (roi->width / threads)*(threads-1);
- else
- data[threads-1].roi.height = roi->height - (roi->height / threads)*(threads-1);
-
- remaining_tasks+=threads;
-
- if (threads==1)
- {
- spawnrender (&data[0], NULL);
- }
- else
- {
- for (i=0; i<threads-1; i++)
- g_thread_pool_push (pool, &data[i], NULL);
- spawnrender (&data[threads-1], NULL);
-
- g_mutex_lock (&mutex);
- while (remaining_tasks!=0)
- g_cond_wait (&cond, &mutex);
- g_mutex_unlock (&mutex);
- }
- }
-#else /* thread free version, could be removed, left behind in case it
- is needed for debugging
- */
{
GeglBuffer *buffer;
- gegl_node_ensure_eval_manager (self, "output", 0);
- buffer = gegl_node_apply_roi (self, "output", roi, 0);
+ buffer = gegl_node_apply_roi (self, roi);
if (buffer && destination_buf)
{
if (destination_buf)
{
- gegl_buffer_get (buffer, 1.0, roi, format, destination_buf, rowstride, GEGL_REPEAT_MODE_ZERO);
+ gegl_buffer_get (buffer, roi, 1.0, format, destination_buf, rowstride, GEGL_ABYSS_NONE);
}
if (scale != 1.0)
{
- g_warning ("Scale %f!=1.0 in blit without cache NYI", scale);
+ g_warning ("scale %f=1.0 in blit without cache", scale);
}
}
- /* and unrefing to ultimately clean it off from the graph */
if (buffer)
g_object_unref (buffer);
}
-#endif
else
if ((flags & GEGL_BLIT_CACHE))
{
@@ -1721,55 +1590,24 @@ gegl_node_get_producer (GeglNode *node,
}
GeglRectangle
-gegl_node_get_bounding_box (GeglNode *root)
+gegl_node_get_bounding_box (GeglNode *self)
{
- GeglRectangle dummy = { 0, 0, 0, 0 };
- GeglVisitor *prepare_visitor;
- GeglVisitor *have_visitor;
- GeglVisitor *finish_visitor;
-
- guchar *id;
- gint i;
-
- GeglPad *pad;
-
- if (!root)
- return dummy;
-
- if (root->valid_have_rect)
- return root->have_rect;
-
- pad = gegl_node_get_pad (root, "output");
- if (pad && pad->node != root)
+ if (!self->valid_have_rect)
{
- root = pad->node;
- }
- if (!pad || !root)
- return dummy;
- g_object_ref (root);
-
- id = g_malloc (1);
+ /* We need to construct an evaluation here because we need
+ * to be sure we use the same logic as the eval manager to
+ * calculate our bounds. We set our rect explicitly because
+ * if we're a meta-op the eval manager may not actually
+ * visit us in prepare.
+ */
- for (i = 0; i < 2; i++)
- {
- prepare_visitor = g_object_new (GEGL_TYPE_PREPARE_VISITOR, "id", id, NULL);
- gegl_visitor_dfs_traverse (prepare_visitor, GEGL_VISITABLE (root));
- g_object_unref (prepare_visitor);
+ GeglEvalManager *eval = gegl_eval_manager_new (self, "output");
+ self->have_rect = gegl_eval_manager_get_bounding_box (eval);
+ self->valid_have_rect = TRUE;
+ g_object_unref (eval);
}
- have_visitor = g_object_new (GEGL_TYPE_HAVE_VISITOR, "id", id, NULL);
- gegl_visitor_dfs_traverse (have_visitor, GEGL_VISITABLE (root));
- g_object_unref (have_visitor);
-
- finish_visitor = g_object_new (GEGL_TYPE_FINISH_VISITOR, "id", id, NULL);
- gegl_visitor_dfs_traverse (finish_visitor, GEGL_VISITABLE (root));
- g_object_unref (finish_visitor);
-
- g_object_unref (root);
- g_free (id);
-
- root->valid_have_rect = TRUE;
- return root->have_rect;
+ return self->have_rect;
}
#if 1
@@ -1807,7 +1645,7 @@ gegl_node_process (GeglNode *self)
input = gegl_node_get_producer (self, "input", NULL);
defined = gegl_node_get_bounding_box (input);
- buffer = gegl_node_apply_roi (input, "output", &defined, 3);
+ buffer = gegl_node_apply_roi (input, &defined);
g_assert (GEGL_IS_BUFFER (buffer));
context = gegl_node_add_context (self, &defined);
@@ -1885,8 +1723,8 @@ gegl_node_add_context (GeglNode *self,
return context;
}
- context = gegl_operation_context_new ();
- context->operation = self->operation;
+ context = gegl_operation_context_new (self->operation);
+
g_hash_table_insert (self->priv->contexts, context_id, context);
g_mutex_unlock (&self->mutex);
return context;
@@ -2082,9 +1920,8 @@ gegl_node_get_cache (GeglNode *node)
"format", format,
NULL);
- /* gegl_node_get_bounding_box must be called at least once to compute
- an initial have_rect for the extent of the cache */
gegl_node_get_bounding_box (node);
+ gegl_buffer_set_extent (GEGL_BUFFER (node->cache), &node->have_rect);
g_signal_connect (G_OBJECT (node->cache), "computed",
(GCallback) gegl_node_computed_event,
@@ -2274,14 +2111,12 @@ graph_source_invalidated (GeglNode *source,
static GeglNode *
-gegl_node_get_pad_proxy (GeglNode *graph,
+gegl_node_get_pad_proxy (GeglNode *node,
const gchar *name,
gboolean is_graph_input)
{
- GeglNode *node = graph;
- GeglPad *pad;
+ GeglPad *pad = gegl_node_get_pad (node, name);
- pad = gegl_node_get_pad (node, name);
if (!pad)
{
GeglNode *nop = NULL;
@@ -2293,7 +2128,7 @@ gegl_node_get_pad_proxy (GeglNode *graph,
nop_pad = gegl_node_get_pad (nop, is_graph_input ? "input" : "output");
g_free (nop_name);
- gegl_node_add_child (graph, nop);
+ gegl_node_add_child (node, nop);
g_object_unref (nop); /* our reference is made by the
gegl_node_add_child call */
@@ -2305,12 +2140,12 @@ gegl_node_get_pad_proxy (GeglNode *graph,
gegl_node_add_pad (node, new_pad);
}
- g_object_set_data (G_OBJECT (nop), "graph", graph);
+ g_object_set_data (G_OBJECT (nop), "graph", node);
if (!is_graph_input)
{
g_signal_connect (G_OBJECT (nop), "invalidated",
- G_CALLBACK (graph_source_invalidated), graph);
+ G_CALLBACK (graph_source_invalidated), node);
}
return nop;
}
diff --git a/gegl/graph/gegl-node.h b/gegl/graph/gegl-node.h
index 76c9f42..c4bb196 100644
--- a/gegl/graph/gegl-node.h
+++ b/gegl/graph/gegl-node.h
@@ -96,6 +96,10 @@ void gegl_node_blit (GeglNode *node,
gint rowstride,
GeglBlitFlags flags);
+void gegl_node_blit_buffer (GeglNode *self,
+ GeglBuffer *buffer,
+ const GeglRectangle *roi);
+
void gegl_node_process (GeglNode *self);
void gegl_node_link (GeglNode *source,
GeglNode *sink);
diff --git a/gegl/graph/gegl-visitor.c b/gegl/graph/gegl-visitor.c
index 0af0500..2e02aa4 100644
--- a/gegl/graph/gegl-visitor.c
+++ b/gegl/graph/gegl-visitor.c
@@ -40,11 +40,9 @@ struct _GeglVisitInfo
enum
{
- PROP_0,
- PROP_ID
+ PROP_0
};
-
static void gegl_visitor_class_init (GeglVisitorClass *klass);
static void gegl_visitor_init (GeglVisitor *self);
static void finalize (GObject *gobject);
@@ -78,15 +76,6 @@ static void visit_pad (GeglVisitor *self,
GeglPad *pad);
static void visit_node (GeglVisitor *self,
GeglNode *node);
-static void set_property (GObject *gobject,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec);
-static void get_property (GObject *gobject,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec);
-
G_DEFINE_TYPE (GeglVisitor, gegl_visitor, G_TYPE_OBJECT)
@@ -99,66 +88,13 @@ gegl_visitor_class_init (GeglVisitorClass *klass)
gobject_class->finalize = finalize;
- klass->visit_pad = visit_pad;
- klass->visit_node = visit_node;
- gobject_class->set_property = set_property;
- gobject_class->get_property = get_property;
-
- g_object_class_install_property (gobject_class, PROP_ID,
- g_param_spec_pointer ("id",
- "evaluation-id",
- "The identifier for the evaluation context",
- G_PARAM_CONSTRUCT |
- G_PARAM_READWRITE));
+ klass->visit_pad = visit_pad;
+ klass->visit_node = visit_node;
}
-
-static void
-set_property (GObject *gobject,
- guint property_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- GeglVisitor *self = GEGL_VISITOR (gobject);
-
- switch (property_id)
- {
- case PROP_ID:
- self->context_id = g_value_get_pointer (value);
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, property_id, pspec);
- break;
- }
-}
-
-static void
-get_property (GObject *gobject,
- guint property_id,
- GValue *value,
- GParamSpec *pspec)
-{
- GeglVisitor *self = GEGL_VISITOR (gobject);
-
- switch (property_id)
- {
- case PROP_ID:
- g_value_set_pointer (value, self->context_id);
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, property_id, pspec);
- break;
- }
-}
-
-
-
static void
gegl_visitor_init (GeglVisitor *self)
{
- self->visits_list = NULL;
self->hash = g_hash_table_new_full (g_direct_hash, g_direct_equal,
NULL,
(GDestroyNotify) visit_info_destroy);
@@ -169,7 +105,6 @@ finalize (GObject *gobject)
{
GeglVisitor *self = GEGL_VISITOR (gobject);
- g_slist_free (self->visits_list);
g_hash_table_destroy (self->hash);
G_OBJECT_CLASS (gegl_visitor_parent_class)->finalize (gobject);
@@ -185,11 +120,6 @@ lookup (GeglVisitor *self,
/* resets the object's data (list of visits and visitable statuses) */
void gegl_visitor_reset (GeglVisitor *self)
{
- if (self->visits_list)
- {
- g_slist_free (self->visits_list);
- self->visits_list = NULL;
- }
g_hash_table_remove_all (self->hash);
}
@@ -280,22 +210,6 @@ set_shared_count (GeglVisitor *self,
visit_info->shared_count = shared_count;
}
-/**
- * gegl_visitor_get_visits_list
- * @self: a #GeglVisitor.
- *
- * Gets a list of the visitables the visitor has visited so far.
- *
- * Returns: A list of the visitables visited by this visitor.
- **/
-GSList *
-gegl_visitor_get_visits_list (GeglVisitor *self)
-{
- g_return_val_if_fail (GEGL_IS_VISITOR (self), NULL);
-
- return self->visits_list;
-}
-
static void
visit_info_destroy (GeglVisitInfo *visit_info)
{
@@ -501,7 +415,6 @@ static void
visit_pad (GeglVisitor *self,
GeglPad *pad)
{
- self->visits_list = g_slist_prepend (self->visits_list, pad);
}
/* should be called by extending classes when their visit_node function
@@ -524,15 +437,4 @@ static void
visit_node (GeglVisitor *self,
GeglNode *node)
{
-#if 0
-#if ENABLE_MT
- g_mutex_lock (node->mutex);
-#endif
-#endif
- self->visits_list = g_slist_prepend (self->visits_list, node);
-#if 0
-#if ENABLE_MT
- g_mutex_unlock (node->mutex);
-#endif
-#endif
}
diff --git a/gegl/graph/gegl-visitor.h b/gegl/graph/gegl-visitor.h
index 9a40585..db9c8e5 100644
--- a/gegl/graph/gegl-visitor.h
+++ b/gegl/graph/gegl-visitor.h
@@ -35,9 +35,7 @@ typedef struct _GeglVisitorClass GeglVisitorClass;
struct _GeglVisitor
{
GObject parent_instance;
- gpointer context_id;
- GSList *visits_list;
GHashTable *hash;
};
@@ -54,7 +52,6 @@ struct _GeglVisitorClass
GType gegl_visitor_get_type (void) G_GNUC_CONST;
-GSList * gegl_visitor_get_visits_list (GeglVisitor *self);
void gegl_visitor_reset (GeglVisitor *self);
void gegl_visitor_visit_visitable (GeglVisitor *self,
GeglVisitable *visitable);
diff --git a/gegl/operation/gegl-operation-context.c b/gegl/operation/gegl-operation-context.c
index bb2df99..eaa7fd7 100644
--- a/gegl/operation/gegl-operation-context.c
+++ b/gegl/operation/gegl-operation-context.c
@@ -195,21 +195,29 @@ gegl_operation_context_add_value (GeglOperationContext *self,
return &property->value;
}
-GeglOperationContext *gegl_operation_context_new (void)
+GeglOperationContext *
+gegl_operation_context_new (GeglOperation *operation)
{
GeglOperationContext *self = g_slice_new0 (GeglOperationContext);
+ self->operation = operation;
return self;
}
-void gegl_operation_context_destroy (GeglOperationContext *self)
+void
+gegl_operation_context_purge (GeglOperationContext *self)
{
-
while (self->property)
{
Property *property = self->property->data;
self->property = g_slist_remove (self->property, property);
property_destroy (property);
}
+}
+
+void
+gegl_operation_context_destroy (GeglOperationContext *self)
+{
+ gegl_operation_context_purge (self);
g_slice_free (GeglOperationContext, self);
}
diff --git a/gegl/operation/gegl-operation-context.h b/gegl/operation/gegl-operation-context.h
index 4561c58..a6340fd 100644
--- a/gegl/operation/gegl-operation-context.h
+++ b/gegl/operation/gegl-operation-context.h
@@ -83,6 +83,8 @@ void gegl_operation_context_get_property (GeglOperationContext *se
const gchar *name,
GValue *value);
+void gegl_operation_context_purge (GeglOperationContext *self);
+
/* the rest of these functions are for internal use only */
void gegl_operation_context_remove_property (GeglOperationContext *self,
@@ -96,7 +98,7 @@ void gegl_operation_context_set_result_rect (GeglOperationContext *no
gint gegl_operation_context_get_level (GeglOperationContext *ctxt);
-GeglOperationContext *gegl_operation_context_new (void);
+GeglOperationContext *gegl_operation_context_new (GeglOperation *operation);
void gegl_operation_context_destroy (GeglOperationContext *opcontext);
G_END_DECLS
diff --git a/gegl/operation/gegl-operation.c b/gegl/operation/gegl-operation.c
index 5d22cf5..d04c2e8 100644
--- a/gegl/operation/gegl-operation.c
+++ b/gegl/operation/gegl-operation.c
@@ -162,6 +162,8 @@ gegl_operation_process (GeglOperation *operation,
return TRUE;
}
+ g_return_val_if_fail (klass->process, FALSE);
+
return klass->process (operation, context, output_pad, result, level);
}
diff --git a/gegl/process/Makefile.am b/gegl/process/Makefile.am
index 8825366..a5dff29 100644
--- a/gegl/process/Makefile.am
+++ b/gegl/process/Makefile.am
@@ -13,26 +13,21 @@ AM_CFLAGS = $(DEP_CFLAGS) $(BABL_CFLAGS)
noinst_LTLIBRARIES = libprocess.la
-#libprocess_publicdir = $(includedir)/gegl-$(GEGL_API_VERSION)/gegl/process
-#libprocess_public_HEADERS = #
+libprocess_publicdir = $(includedir)/gegl-$(GEGL_API_VERSION)
+libprocess_public_HEADERS = gegl-graph-debug.h
libprocess_la_SOURCES = \
- gegl-need-visitor.c \
- gegl-debug-rect-visitor.c \
gegl-eval-manager.c \
- gegl-eval-visitor.c \
- gegl-finish-visitor.c \
- gegl-have-visitor.c \
- gegl-prepare-visitor.c \
+ gegl-graph-traversal.c \
+ gegl-graph-traversal-debug.c \
+ gegl-list-visitor.c \
gegl-processor.c \
\
- gegl-need-visitor.h \
- gegl-debug-rect-visitor.h \
gegl-eval-manager.h \
- gegl-eval-visitor.h \
- gegl-finish-visitor.h \
- gegl-have-visitor.h \
- gegl-prepare-visitor.h \
+ gegl-graph-debug.h \
+ gegl-graph-traversal.h \
+ gegl-graph-traversal-private.h \
+ gegl-list-visitor.h \
gegl-processor.h
#libprocess_la_SOURCES = $(lib_process_sources) $(libprocess_public_HEADERS)
diff --git a/gegl/process/gegl-eval-manager.c b/gegl/process/gegl-eval-manager.c
index bf9d82a..8fa799c 100644
--- a/gegl/process/gegl-eval-manager.c
+++ b/gegl/process/gegl-eval-manager.c
@@ -15,6 +15,7 @@
*
* Copyright 2003 Calvin Williamson
* 2006 Øyvind Kolås
+ * 2013 Daniel Sabo
*/
#include "config.h"
@@ -24,19 +25,11 @@
#include "gegl.h"
#include "gegl-types-internal.h"
#include "gegl-eval-manager.h"
-#include "gegl-eval-visitor.h"
-#include "gegl-debug-rect-visitor.h"
-#include "gegl-need-visitor.h"
-#include "gegl-have-visitor.h"
#include "gegl-instrument.h"
+
#include "graph/gegl-node.h"
-#include "gegl-prepare-visitor.h"
-#include "gegl-finish-visitor.h"
-#include "graph/gegl-pad.h"
-#include "graph/gegl-visitable.h"
-#include "operation/gegl-operation.h"
-#include <stdlib.h>
+#include "process/gegl-graph-traversal.h"
static void gegl_eval_manager_class_init (GeglEvalManagerClass *klass);
static void gegl_eval_manager_init (GeglEvalManager *self);
@@ -55,44 +48,29 @@ gegl_eval_manager_class_init (GeglEvalManagerClass *klass)
static void
gegl_eval_manager_init (GeglEvalManager *self)
{
- GeglRectangle roi = { 0, 0, -1, -1 };
- gpointer context_id = self;
-
- self->roi = roi;
- self->prepare_visitor = g_object_new (GEGL_TYPE_PREPARE_VISITOR, "id", context_id, NULL);
- self->have_visitor = g_object_new (GEGL_TYPE_HAVE_VISITOR, "id", context_id, NULL);
- self->eval_visitor = g_object_new (GEGL_TYPE_EVAL_VISITOR, "id", context_id, NULL);
- self->need_visitor = g_object_new (GEGL_TYPE_NEED_VISITOR, "id", context_id, NULL);
- self->finish_visitor = g_object_new (GEGL_TYPE_FINISH_VISITOR, "id", context_id, NULL);
- self->state = UNINITIALIZED;
+ self->state = INVALID;
+ self->pad_name = NULL;
+ self->traversal = NULL;
}
static void
gegl_eval_manager_finalize (GObject *self_object)
{
GeglEvalManager *self = GEGL_EVAL_MANAGER (self_object);
-#if 0
- GeglNode *root;
- GeglPad *pad;
- root=self->node;
- pad = gegl_node_get_pad (root, self->pad_name);
- /* Use the redirect output NOP of a graph instead of a graph if a traversal
- * is attempted directly on a graph */
- if (pad && pad->node != self->node)
- root = pad->node;
- else
- root = self->node;
- gegl_visitor_reset (self->finish_visitor);
- gegl_visitor_dfs_traverse (self->finish_visitor, GEGL_VISITABLE (root));
-#endif
+ if (self->pad_name)
+ {
+ g_free (self->pad_name);
+ self->pad_name = NULL;
+ }
+
+ if (self->traversal)
+ {
+ gegl_graph_free (self->traversal);
+ self->traversal = NULL;
+ }
- g_object_unref (self->prepare_visitor);
- g_object_unref (self->have_visitor);
- g_object_unref (self->eval_visitor);
- g_object_unref (self->need_visitor);
- g_object_unref (self->finish_visitor);
- g_free (self->pad_name);
+ g_signal_handlers_disconnect_by_data (self->node, self);
G_OBJECT_CLASS (gegl_eval_manager_parent_class)->finalize (self_object);
}
@@ -103,146 +81,54 @@ gegl_eval_manager_change_notification (GObject *gobject,
gpointer user_data)
{
GeglEvalManager *manager = GEGL_EVAL_MANAGER (user_data);
-
- if (manager->node != NULL)
- {
- gpointer context_id = manager;
- GeglOperationContext *context = gegl_node_get_context (manager->node,
- context_id);
- if (context != NULL)
- {
- /* If the node is changed we can't use the cache any longer */
- context->cached = FALSE;
- }
- }
-
- if (manager->state != UNINITIALIZED)
- {
- manager->state = NEED_REDO_PREPARE_AND_HAVE_RECT_TRAVERSAL;
- }
+ manager->state = INVALID;
return FALSE;
}
-
-GeglBuffer *
-gegl_eval_manager_apply (GeglEvalManager *self)
+void
+gegl_eval_manager_prepare (GeglEvalManager *self)
{
- GeglNode *root;
- GeglBuffer *object;
- GeglPad *pad;
- glong time = gegl_ticks ();
- gpointer context_id = self;
-
- g_assert (GEGL_IS_EVAL_MANAGER (self));
-
- gegl_instrument ("gegl", "process", 0);
+ g_return_if_fail (GEGL_IS_EVAL_MANAGER (self));
+ g_return_if_fail (GEGL_IS_NODE (self->node));
- root=self->node;
- pad = gegl_node_get_pad (root, self->pad_name);
- /* Use the redirect output NOP of a graph instead of a graph if a traversal
- * is attempted directly on a graph */
- if (pad && pad->node != self->node)
- root = pad->node;
- else
- root = self->node;
- g_assert (root);
-
- g_object_ref (root);
-
- /* do the necessary set-up work (all using depth first traversal) */
- switch (self->state)
+ if (self->state != READY)
{
- case UNINITIALIZED:
- /* Set up the node's context and "needed rectangle"*/
- gegl_visitor_reset (self->prepare_visitor);
- gegl_visitor_dfs_traverse (self->prepare_visitor, GEGL_VISITABLE (root));
- /* No idea why there is a second call */
- gegl_visitor_reset (self->prepare_visitor);
- gegl_visitor_dfs_traverse (self->prepare_visitor, GEGL_VISITABLE (root));
- case NEED_REDO_PREPARE_AND_HAVE_RECT_TRAVERSAL:
- /* sets up the node's rect (bounding box) */
- gegl_visitor_reset (self->have_visitor);
- gegl_visitor_dfs_traverse (self->have_visitor, GEGL_VISITABLE (root));
- case NEED_CONTEXT_SETUP_TRAVERSAL:
-
- gegl_visitor_reset (self->prepare_visitor);
- gegl_visitor_dfs_traverse (self->prepare_visitor, GEGL_VISITABLE (root));
- self->state = NEED_CONTEXT_SETUP_TRAVERSAL;
- }
-
- /* set up the root node */
- if (self->roi.width == -1 &&
- self->roi.height == -1)
- {
- self->roi = root->have_rect;
- }
+ if (!self->traversal)
+ self->traversal = gegl_graph_build (self->node);
+ else
+ gegl_graph_rebuild (self->traversal, self->node);
- gegl_node_set_need_rect (root, context_id, &self->roi);
+ gegl_graph_prepare (self->traversal);
- /* set up the context's rectangle (breadth first traversal) */
- gegl_visitor_reset (self->need_visitor);
-
- /* should the need rect be moved into the context, making this
- * part of gegl re-entrable without locking?.. or does that
- * hamper other useful API that depends on the need_rect to be
- * in the nodes?
- */
- gegl_visitor_bfs_traverse (self->need_visitor, GEGL_VISITABLE (root));
+ self->state = READY;
+ }
+}
-#if 0
- if (g_getenv ("GEGL_DEBUG_RECTS") != NULL)
- {
- GeglVisitor *debug_rect_visitor;
+GeglRectangle
+gegl_eval_manager_get_bounding_box (GeglEvalManager *self)
+{
+ gegl_eval_manager_prepare (self);
+ return gegl_graph_get_bounding_box (self->traversal);
+}
- g_warning ("---------------------");
- debug_rect_visitor = g_object_new (GEGL_TYPE_DEBUG_RECT_VISITOR, "id", context_id, NULL);
- gegl_visitor_dfs_traverse (debug_rect_visitor, GEGL_VISITABLE (root));
- g_object_unref (debug_rect_visitor);
- }
-#endif
+GeglBuffer *
+gegl_eval_manager_apply (GeglEvalManager *self,
+ const GeglRectangle *roi)
+{
+ GeglBuffer *object;
- /* now let's do the real work */
- gegl_visitor_reset (self->eval_visitor);
- if (pad)
- {
- gegl_visitor_dfs_traverse (self->eval_visitor, GEGL_VISITABLE (pad));
- }
- else
- { /* pull on the input of our sink if no pad of the given pad-name
- was available, we take this as an indication that we're in fact
- doing processing on a sink (and the ROI inidcates the data to
- be written, note that GEGL might subdivide this roi
- in its processing.
- */
- GeglPad *pad = gegl_node_get_pad (root, "input");
- gegl_visitor_dfs_traverse (self->eval_visitor, GEGL_VISITABLE (pad));
- }
+ g_return_val_if_fail (GEGL_IS_EVAL_MANAGER (self), NULL);
+ g_return_val_if_fail (GEGL_IS_NODE (self->node), NULL);
- if (pad)
- {
- /* extract returned object before running finish visitor */
- GValue value = { 0, };
- g_value_init (&value, G_TYPE_OBJECT);
- gegl_operation_context_get_property (gegl_node_get_context (root, context_id),
- "output", &value);
- object = g_value_get_object (&value);
- g_object_ref (object);/* salvage buffer from finalization */
- g_value_unset (&value);
- }
+ if (roi->width <= 0 || roi->height <= 0)
+ return NULL;
- /* do the clean up */
- gegl_visitor_reset (self->finish_visitor);
- gegl_visitor_dfs_traverse (self->finish_visitor, GEGL_VISITABLE (root));
+ gegl_eval_manager_prepare (self);
- g_object_unref (root);
- time = gegl_ticks () - time;
- gegl_instrument ("gegl", "process", time);
+ gegl_graph_prepare_request (self->traversal, roi);
+ object = gegl_graph_process (self->traversal);
- if (!pad || !G_IS_OBJECT (object))
- {
- return NULL;
- }
return object;
}
@@ -250,14 +136,19 @@ GeglEvalManager * gegl_eval_manager_new (GeglNode *node,
const gchar *pad_name)
{
GeglEvalManager *self = g_object_new (GEGL_TYPE_EVAL_MANAGER, NULL);
+
g_assert (GEGL_IS_NODE (node));
+
+ /* FIXME: This should be a weakref */
self->node = node;
+
if (pad_name)
self->pad_name = g_strdup (pad_name);
else
self->pad_name = g_strdup ("output");
- /*g_signal_connect (G_OBJECT (self->node->operation), "notify", G_CALLBACK
(gegl_eval_manager_change_notification), self);*/
- g_signal_connect (G_OBJECT (self->node), "invalidated", G_CALLBACK
(gegl_eval_manager_change_notification), self);
- g_signal_connect (G_OBJECT (self->node), "notify", G_CALLBACK (gegl_eval_manager_change_notification),
self);
+
+ g_signal_connect (G_OBJECT (self->node), "invalidated",
+ G_CALLBACK (gegl_eval_manager_change_notification),
+ self);
return self;
}
diff --git a/gegl/process/gegl-eval-manager.h b/gegl/process/gegl-eval-manager.h
index bd7263c..41a2585 100644
--- a/gegl/process/gegl-eval-manager.h
+++ b/gegl/process/gegl-eval-manager.h
@@ -14,6 +14,7 @@
* License along with GEGL; if not, see <http://www.gnu.org/licenses/>.
*
* Copyright 2003 Calvin Williamson
+ * Copyright 2013 Daniel Sabo
*/
#ifndef __GEGL_EVAL_MANAGER_H__
@@ -21,23 +22,15 @@
#include "gegl-types-internal.h"
#include "buffer/gegl-buffer-types.h"
+#include "process/gegl-graph-traversal.h"
G_BEGIN_DECLS
typedef enum
{
- UNINITIALIZED,
-
- /* means we need to redo an extra prepare and have_rect
- * traversal
- */
- NEED_REDO_PREPARE_AND_HAVE_RECT_TRAVERSAL,
-
- /* means we need a prepare traversal to set up the contexts on the
- * nodes
- */
- NEED_CONTEXT_SETUP_TRAVERSAL
+ INVALID,
+ READY
} GeglEvalManagerStates;
@@ -56,19 +49,9 @@ struct _GeglEvalManager
GObject parent_instance;
GeglNode *node;
gchar *pad_name;
- GeglRectangle roi;
- /* whether we can fire off rendering requests straight
- * away or we have to re-prepare etc of the graph
- */
- GeglEvalManagerStates state;
-
- /* we keep these objects around, they are too expensive to throw away */
- GeglVisitor *prepare_visitor;
- GeglVisitor *need_visitor;
- GeglVisitor *eval_visitor;
- GeglVisitor *have_visitor;
- GeglVisitor *finish_visitor;
+ GeglGraphTraversal *traversal;
+ GeglEvalManagerStates state;
};
@@ -80,7 +63,11 @@ struct _GeglEvalManagerClass
GType gegl_eval_manager_get_type (void) G_GNUC_CONST;
-GeglBuffer * gegl_eval_manager_apply (GeglEvalManager *self);
+void gegl_eval_manager_prepare (GeglEvalManager *self);
+GeglRectangle gegl_eval_manager_get_bounding_box (GeglEvalManager *self);
+
+GeglBuffer * gegl_eval_manager_apply (GeglEvalManager *self,
+ const GeglRectangle *roi);
GeglEvalManager * gegl_eval_manager_new (GeglNode *node,
const gchar *pad_name);
diff --git a/gegl/process/gegl-graph-debug.h b/gegl/process/gegl-graph-debug.h
new file mode 100644
index 0000000..49c6810
--- /dev/null
+++ b/gegl/process/gegl-graph-debug.h
@@ -0,0 +1,25 @@
+/* This file is part of GEGL.
+ *
+ * This library 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.
+ *
+ * This library 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_GRAPH_DEBUG_H__
+#define __GEGL_GRAPH_DEBUG_H__
+
+void gegl_graph_dump_outputs (GeglNode *node);
+void gegl_graph_dump_reqeust (GeglNode *node, const GeglRectangle *roi);
+
+#endif /* __GEGL_GRAPH_DEBUG_H__ */
diff --git a/gegl/process/gegl-graph-traversal-debug.c b/gegl/process/gegl-graph-traversal-debug.c
new file mode 100644
index 0000000..4771f55
--- /dev/null
+++ b/gegl/process/gegl-graph-traversal-debug.c
@@ -0,0 +1,95 @@
+/* This file is part of GEGL.
+ *
+ * This library 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.
+ *
+ * This library 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 "gegl-types-internal.h"
+#include "gegl.h"
+#include "gegl-utils.h"
+
+#include "graph/gegl-node.h"
+#include "graph/gegl-pad.h"
+
+#include "process/gegl-graph-debug.h"
+#include "process/gegl-graph-traversal.h"
+#include "process/gegl-graph-traversal-private.h"
+
+#include "operation/gegl-operation.h"
+#include "operation/gegl-operation-context.h"
+
+#include <stdio.h>
+
+void
+gegl_graph_dump_outputs (GeglNode *node)
+{
+ GeglGraphTraversal *path = gegl_graph_build (node);
+ GList *list_iter = NULL;
+
+ gegl_graph_prepare (path);
+
+ for (list_iter = path->dfs_path; list_iter; list_iter = list_iter->next)
+ {
+ GeglNode *cur_node = GEGL_NODE (list_iter->data);
+ if (gegl_node_get_pad (cur_node, "output"))
+ {
+ const Babl *format = gegl_operation_get_format (cur_node->operation, "output");
+ printf ("%s: output=%s\n", gegl_node_get_debug_name (cur_node),
+ format ? babl_get_name (format) : "N/A");
+ }
+ else
+ {
+ printf ("%s: sink\n", gegl_node_get_debug_name (cur_node));
+ }
+
+ if (cur_node->valid_have_rect)
+ {
+ printf (" bounds: ");
+ gegl_rectangle_dump (&cur_node->have_rect);
+ }
+ }
+
+ gegl_graph_free (path);
+}
+
+void
+gegl_graph_dump_reqeust (GeglNode *node,
+ const GeglRectangle *roi)
+{
+ GeglGraphTraversal *path = gegl_graph_build (node);
+ GList *list_iter = NULL;
+
+ gegl_graph_prepare (path);
+ gegl_graph_prepare_request (path, roi);
+
+ for (list_iter = path->dfs_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);
+
+ if (!context->cached)
+ printf ("%s: result: ", gegl_node_get_debug_name (cur_node));
+ else
+ printf ("%s: result (cached): ", gegl_node_get_debug_name (cur_node));
+ gegl_rectangle_dump (gegl_operation_context_get_need_rect (context));
+ }
+
+ gegl_graph_free (path);
+}
+
diff --git a/gegl/process/gegl-graph-traversal-private.h b/gegl/process/gegl-graph-traversal-private.h
new file mode 100644
index 0000000..cad0856
--- /dev/null
+++ b/gegl/process/gegl-graph-traversal-private.h
@@ -0,0 +1,31 @@
+/* This file is part of GEGL.
+ *
+ * This library 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.
+ *
+ * This library 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_GRAPH_TRAVERSAL_PRIVATE_H__
+#define __GEGL_GRAPH_TRAVERSAL_PRIVATE_H__
+
+struct _GeglGraphTraversal
+{
+ GHashTable *contexts;
+ GList *dfs_path;
+ GList *bfs_path;
+ gboolean rects_dirty;
+ GeglBuffer *shared_empty;
+};
+
+#endif /* __GEGL_GRAPH_TRAVERSAL_PRIVATE_H__ */
diff --git a/gegl/process/gegl-graph-traversal.c b/gegl/process/gegl-graph-traversal.c
new file mode 100644
index 0000000..0ce9da0
--- /dev/null
+++ b/gegl/process/gegl-graph-traversal.c
@@ -0,0 +1,453 @@
+/* This file is part of GEGL.
+ *
+ * This library 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.
+ *
+ * This library 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 "gegl-types-internal.h"
+#include "gegl.h"
+#include "gegl-utils.h"
+#include "gegl-debug.h"
+
+#include "buffer/gegl-region.h"
+
+#include "graph/gegl-node.h"
+#include "graph/gegl-pad.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"
+
+typedef struct
+{
+ const gchar *name;
+ GeglOperationContext *context;
+} ContextConnection;
+
+static void free_context_connection (gpointer concon);
+static GList *gegl_graph_get_connected_output_contexts (GeglGraphTraversal *path,
+ GeglPad *output_pad);
+static void _gegl_graph_do_build (GeglGraphTraversal *path,
+ GeglNode *node);
+static GeglBuffer *gegl_graph_get_shared_empty (GeglGraphTraversal *path);
+
+static void
+_gegl_graph_do_build (GeglGraphTraversal *path, GeglNode *node)
+{
+ GeglPad *pad = NULL;
+ GeglListVisitor *list_visitor = g_object_new (GEGL_TYPE_LIST_VISITOR, NULL);
+
+ /* 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");
+ if (pad)
+ {
+ node = gegl_pad_get_node (pad);
+ }
+ else
+ {
+ pad = gegl_node_get_pad (node, "input");
+ if (pad)
+ 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));
+ path->contexts = g_hash_table_new_full (NULL,
+ NULL,
+ NULL,
+ (GDestroyNotify)gegl_operation_context_destroy);
+ path->rects_dirty = FALSE;
+ g_object_unref (list_visitor);
+}
+
+/**
+ * gegl_graph_build:
+ * @node: The node to build a traversal for
+ *
+ * Build a traversal for @node.
+ *
+ * Return value: A new #GeglGraphTraversal
+ */
+GeglGraphTraversal *
+gegl_graph_build (GeglNode *node)
+{
+ GeglGraphTraversal *result = g_new0 (GeglGraphTraversal, 1);
+
+ _gegl_graph_do_build (result, node);
+
+ return result;
+}
+
+/**
+ * gegl_graph_rebuild:
+ * @path: The traversal object to reuse
+ * @node: The node to build a traversal for
+ *
+ * Build a traversal for @node, reusing the scratch objects
+ * from @path where possible.
+ */
+void
+gegl_graph_rebuild (GeglGraphTraversal *path, GeglNode *node)
+{
+ g_list_free (path->dfs_path);
+ g_list_free (path->bfs_path);
+ g_hash_table_unref (path->contexts);
+
+ /* Replaces everything but shared_empty */
+ _gegl_graph_do_build (path, node);
+}
+
+void
+gegl_graph_free (GeglGraphTraversal *path)
+{
+ g_list_free (path->dfs_path);
+ g_list_free (path->bfs_path);
+ g_hash_table_unref (path->contexts);
+ if (path->shared_empty)
+ g_object_unref (path->shared_empty);
+
+ g_free (path);
+}
+
+
+/**
+ * gegl_graph_get_bounding_box:
+ * @path: The traversal path
+ *
+ * Get output bounding box for this graph, which is the
+ * have rect of the final node.
+ *
+ * Return value: Output rect of @path
+ */
+GeglRectangle
+gegl_graph_get_bounding_box (GeglGraphTraversal *path)
+{
+ GeglNode *node = GEGL_NODE (g_list_last (path->dfs_path)->data);
+ if (node->valid_have_rect)
+ {
+ return node->have_rect;
+ }
+ return *GEGL_RECTANGLE(0, 0, 0, 0);
+}
+
+/**
+ * gegl_graph_prepare:
+ * @path: The traversal path
+ *
+ * Prepare all nodes, initializing their output formats and have rects.
+ */
+void
+gegl_graph_prepare (GeglGraphTraversal *path)
+{
+ GList *list_iter = NULL;
+
+ for (list_iter = path->dfs_path; list_iter; list_iter = list_iter->next)
+ {
+ GeglNode *node = GEGL_NODE (list_iter->data);
+ GeglOperation *operation = node->operation;
+
+ g_mutex_lock (&node->mutex);
+
+ gegl_operation_prepare (operation);
+ node->have_rect = gegl_operation_get_bounding_box (operation);
+ node->valid_have_rect = TRUE;
+
+ if (node->cache)
+ {
+ gegl_buffer_set_extent (GEGL_BUFFER (node->cache),
+ &node->have_rect);
+ }
+
+ g_mutex_unlock (&node->mutex);
+
+ if (!g_hash_table_contains (path->contexts, node))
+ {
+ GeglOperationContext *context = gegl_operation_context_new (node->operation);
+
+ g_hash_table_insert (path->contexts,
+ node,
+ context);
+ }
+ }
+}
+
+/**
+ * gegl_graph_prepare_request:
+ * @path: The traversal path
+ * @request_roi: The request rect
+ *
+ * Prepare the graph to render request_roi, this will calculate
+ * the area that needs to be rendered from each node in the
+ * graph to fulfill this request.
+ */
+void
+gegl_graph_prepare_request (GeglGraphTraversal *path,
+ const GeglRectangle *request_roi)
+{
+ GList *list_iter = NULL;
+ static const GeglRectangle empty_rect = {0, 0, 0, 0};
+
+ g_return_if_fail (path->bfs_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)
+ {
+ GeglNode *node = GEGL_NODE (list_iter->data);
+ GeglOperationContext *context = g_hash_table_lookup (path->contexts, node);
+
+ /* We only need to reset the need rect, result will always get overwritten */
+ gegl_operation_context_set_need_rect (context, &empty_rect);
+
+ /* Reset cached status, because the rect we need may have changed */
+ context->cached = FALSE;
+ }
+ }
+
+ path->rects_dirty = TRUE;
+
+ {
+ /* Prep the first node */
+ GeglNode *node = GEGL_NODE (path->bfs_path->data);
+ GeglOperationContext *context = g_hash_table_lookup (path->contexts, node);
+ GeglRectangle new_need;
+
+ g_return_if_fail (context);
+
+ gegl_rectangle_intersect (&new_need, &node->have_rect, request_roi);
+
+ gegl_operation_context_set_need_rect (context, &new_need);
+ gegl_operation_context_set_result_rect (context, &new_need);
+ }
+
+ /* Iterate over all the nodes and propagate the requested rectangle */
+ for (list_iter = path->bfs_path; list_iter; list_iter = list_iter->next)
+ {
+ GeglNode *node = GEGL_NODE (list_iter->data);
+ GeglOperation *operation = node->operation;
+ GeglOperationContext *context;
+ GeglRectangle *request;
+ GSList *input_pads;
+
+ context = g_hash_table_lookup (path->contexts, node);
+ g_return_if_fail (context);
+
+ request = gegl_operation_context_get_need_rect (context);
+
+ if (request->width == 0 || request->height == 0)
+ {
+ gegl_operation_context_set_result_rect (context, &empty_rect);
+ }
+ else if (node->cache &&
+ gegl_region_rect_in (node->cache->valid_region, request) == GEGL_OVERLAP_RECTANGLE_IN)
+ {
+ /* This node is cached and the cache fulfills our need rect */
+ context->cached = TRUE;
+ gegl_operation_context_set_result_rect (context, &empty_rect);
+ }
+ else
+ {
+ /* FIXME: We could trim this down based on the cache, instead of being all or nothing */
+ gegl_operation_context_set_result_rect (context, request);
+
+ for (input_pads = node->input_pads; input_pads; input_pads = input_pads->next)
+ {
+ GeglPad *source_pad = gegl_pad_get_connected_to (input_pads->data);
+
+ if (source_pad)
+ {
+ GeglNode *source_node = gegl_pad_get_node (source_pad);
+ GeglOperationContext *source_context = g_hash_table_lookup (path->contexts, source_node);
+ const gchar *pad_name = gegl_pad_get_name (input_pads->data);
+
+ GeglRectangle rect, current_need, new_need;
+
+ /* Combine this need rect with any existing request */
+ rect = gegl_operation_get_required_for_output (operation, pad_name, request);
+ current_need = *gegl_operation_context_get_need_rect (source_context);
+
+ gegl_rectangle_bounding_box (&new_need, &rect, ¤t_need);
+
+ /* Limit request to the nodes output */
+ gegl_rectangle_intersect (&new_need, &source_node->have_rect, &new_need);
+
+ gegl_operation_context_set_need_rect (source_context, &new_need);
+ }
+ }
+ }
+ }
+}
+
+void
+free_context_connection (gpointer concon)
+{
+ g_free (concon);
+}
+
+GList *
+gegl_graph_get_connected_output_contexts (GeglGraphTraversal *path,
+ GeglPad *output_pad)
+{
+ GList *result = NULL;
+ GSList *targets = gegl_pad_get_connections (output_pad);
+ GSList *targets_iter;
+ for (targets_iter = targets; targets_iter; targets_iter = g_slist_next (targets_iter))
+ {
+ GeglNode *target_node = gegl_connection_get_sink_node (targets_iter->data);
+ GeglOperationContext *target_context = g_hash_table_lookup (path->contexts, target_node);
+
+ /* Only include this target if it's part of the current path */
+ if (target_context)
+ {
+ const gchar *target_pad_name = gegl_pad_get_name (gegl_connection_get_sink_pad
(targets_iter->data));
+
+ ContextConnection *result_element = g_new0 (ContextConnection, 1);
+ result_element->name = target_pad_name;
+ result_element->context = target_context;
+
+ result = g_list_prepend (result, result_element);
+ }
+ }
+ return result;
+}
+
+GeglBuffer *
+gegl_graph_get_shared_empty (GeglGraphTraversal *path)
+{
+ if (!path->shared_empty)
+ {
+ path->shared_empty = gegl_buffer_new_ram (GEGL_RECTANGLE (0, 0, 0, 0),
+ babl_format ("RGBA float"));
+ gegl_object_set_has_forked (path->shared_empty);
+ }
+ return path->shared_empty;
+}
+
+
+/**
+ * gegl_graph_process:
+ * @path: The traversal path
+ *
+ * Process the prepared request. This will return the
+ * resulting buffer from the final node, or NULL if
+ * that node is a sink.
+ *
+ * If gegl_graph_prepare_request has not been called
+ * the behavior of this function is undefined.
+ *
+ * Return value: (transfer full): The result of the graph, or NULL if
+ * there is no output pad.
+ */
+GeglBuffer *
+gegl_graph_process (GeglGraphTraversal *path)
+{
+ GList *list_iter = NULL;
+ GeglBuffer *result = NULL;
+ GeglOperationContext *context = NULL;
+ GeglOperationContext *last_context = NULL;
+
+ for (list_iter = path->dfs_path; list_iter; list_iter = list_iter->next)
+ {
+ GeglNode *node = GEGL_NODE (list_iter->data);
+ GeglOperation *operation = node->operation;
+ GeglBuffer *operation_result = NULL;
+ g_return_val_if_fail (node, NULL);
+ g_return_val_if_fail (operation, NULL);
+
+ if (last_context)
+ gegl_operation_context_purge (last_context);
+
+ context = g_hash_table_lookup (path->contexts, node);
+ g_return_val_if_fail (context, NULL);
+
+ GEGL_NOTE (GEGL_DEBUG_PROCESS,
+ "Will process %s result_rect = %d, %d %d×%d",
+ gegl_node_get_debug_name (node),
+ context->result_rect.x, context->result_rect.y, context->result_rect.width,
context->result_rect.height);
+
+ if (context->need_rect.width > 0 && context->need_rect.height > 0)
+ {
+ if (context->cached)
+ {
+ GEGL_NOTE (GEGL_DEBUG_PROCESS,
+ "Using cached result for %s",
+ gegl_node_get_debug_name (node));
+ operation_result = GEGL_BUFFER (node->cache);
+ }
+ else
+ {
+ /* Guarantee input pad */
+ if (gegl_node_has_pad (node, "input") &&
+ !gegl_operation_context_get_object (context, "input"))
+ {
+ gegl_operation_context_set_object (context, "input", G_OBJECT
(gegl_graph_get_shared_empty(path)));
+ }
+
+ gegl_operation_process (operation, context, "output", &context->need_rect, context->level);
+ operation_result = GEGL_BUFFER (gegl_operation_context_get_object (context, "output"));
+ }
+ }
+ else
+ {
+ operation_result = NULL;
+ }
+
+ if (operation_result)
+ {
+ GeglPad *output_pad = gegl_node_get_pad (node, "output");
+ GList *targets = gegl_graph_get_connected_output_contexts (path, output_pad);
+ GList *targets_iter;
+
+ GEGL_NOTE (GEGL_DEBUG_PROCESS,
+ "Will deliver the results of %s:%s to %d targets",
+ gegl_node_get_debug_name (node),
+ "output",
+ g_list_length (targets));
+
+ if (g_list_length (targets) > 1)
+ gegl_object_set_has_forked (operation_result);
+
+ for (targets_iter = targets; targets_iter; targets_iter = g_list_next (targets_iter))
+ {
+ ContextConnection *target_con = targets_iter->data;
+ gegl_operation_context_set_object (target_con->context, target_con->name, G_OBJECT
(operation_result));
+ }
+
+ g_list_free_full (targets, free_context_connection);
+ }
+
+ last_context = context;
+ }
+
+ if (last_context)
+ {
+ GValue *value = gegl_operation_context_get_value (context, "output");
+ if (value)
+ result = g_value_dup_object (value);
+ gegl_operation_context_purge (last_context);
+ }
+
+ return result;
+}
diff --git a/gegl/process/gegl-graph-traversal.h b/gegl/process/gegl-graph-traversal.h
new file mode 100644
index 0000000..34b360b
--- /dev/null
+++ b/gegl/process/gegl-graph-traversal.h
@@ -0,0 +1,17 @@
+#ifndef __GEGL_GRAPH_TRAVERSAL_H__
+#define __GEGL_GRAPH_TRAVERSAL_H__
+
+typedef struct _GeglGraphTraversal GeglGraphTraversal;
+
+void gegl_graph_dfs_dump (GeglNode *);
+
+GeglGraphTraversal *gegl_graph_build (GeglNode *node);
+void gegl_graph_rebuild (GeglGraphTraversal *path, GeglNode *node);
+void gegl_graph_free (GeglGraphTraversal *path);
+
+void gegl_graph_prepare (GeglGraphTraversal *path);
+void gegl_graph_prepare_request (GeglGraphTraversal *path, const GeglRectangle *roi);
+GeglBuffer *gegl_graph_process (GeglGraphTraversal *path);
+GeglRectangle gegl_graph_get_bounding_box (GeglGraphTraversal *path);
+
+#endif /* __GEGL_GRAPH_TRAVERSAL_H__ */
diff --git a/gegl/process/gegl-list-visitor.c b/gegl/process/gegl-list-visitor.c
new file mode 100644
index 0000000..8d9a6c3
--- /dev/null
+++ b/gegl/process/gegl-list-visitor.c
@@ -0,0 +1,120 @@
+/* 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.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 void 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)
+{
+ gegl_visitor_reset (GEGL_VISITOR (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 void
+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);
+}
diff --git a/gegl/process/gegl-list-visitor.h b/gegl/process/gegl-list-visitor.h
new file mode 100644
index 0000000..89c100a
--- /dev/null
+++ b/gegl/process/gegl-list-visitor.h
@@ -0,0 +1,60 @@
+/* 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__ */
diff --git a/gegl/process/gegl-processor.c b/gegl/process/gegl-processor.c
index e9cb616..16c9925 100644
--- a/gegl/process/gegl-processor.c
+++ b/gegl/process/gegl-processor.c
@@ -34,6 +34,7 @@
#include "graph/gegl-visitor.h"
#include "graph/gegl-visitable.h"
+#include "process/gegl-list-visitor.h"
#include "opencl/gegl-cl.h"
@@ -164,8 +165,7 @@ gegl_processor_finalize (GObject *self_object)
if (processor->context)
{
- GeglCache *cache = gegl_node_get_cache (processor->input);
- gegl_node_remove_context (processor->node, cache);
+ gegl_operation_context_destroy (processor->context);
}
if (processor->node)
@@ -365,8 +365,10 @@ gegl_processor_set_rectangle (GeglProcessor *processor,
cache = gegl_node_get_cache (processor->input);
- if (!gegl_node_get_context (processor->node, cache))
- processor->context = gegl_node_add_context (processor->node, cache);
+ if (!processor->context)
+ {
+ processor->context = gegl_operation_context_new (processor->node->operation);
+ }
g_value_init (&value, GEGL_TYPE_BUFFER);
g_value_set_object (&value, cache);
@@ -494,10 +496,11 @@ render_rectangle (GeglProcessor *processor)
/* create a buffer and initialise it */
guchar *buf;
- gegl_region_union_with_rect (cache->valid_region, dr);
buf = g_malloc (dr->width * dr->height * pxsize);
g_assert (buf);
+ /* FIXME: Check if the node caches naturaly, if so the buffer_set call isn't needed */
+
/* do the image calculations using the buffer */
gegl_node_blit (processor->input, 1.0, dr, cache->format, buf,
GEGL_AUTO_ROWSTRIDE, GEGL_BLIT_DEFAULT);
@@ -747,19 +750,16 @@ gegl_processor_work (GeglProcessor *processor,
gdouble *progress)
{
gboolean more_work = FALSE;
- GeglCache *cache = gegl_node_get_cache (processor->input);
if (gegl_config()->use_opencl)
{
if (gegl_cl_is_accelerated ()
&& processor->chunk_size != GEGL_CL_CHUNK_SIZE)
{
- GeglVisitor *visitor = g_object_new (GEGL_TYPE_VISITOR, NULL);
- GSList *iterator = NULL;
- GSList *visits_list = NULL;
- gegl_visitor_reset (visitor);
- gegl_visitor_dfs_traverse (visitor, GEGL_VISITABLE (processor->node));
- visits_list = gegl_visitor_get_visits_list (visitor);
+ 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->node));
for (iterator = visits_list; iterator; iterator = iterator->next)
{
@@ -772,6 +772,7 @@ gegl_processor_work (GeglProcessor *processor,
}
}
+ g_list_free (visits_list);
g_object_unref (visitor);
}
}
@@ -794,7 +795,7 @@ gegl_processor_work (GeglProcessor *processor,
processor->context,
"output" /* ignored output_pad */,
&processor->context->result_rect, processor->context->level);
- gegl_node_remove_context (processor->node, cache);
+ gegl_operation_context_destroy (processor->context);
processor->context = NULL;
return TRUE;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]