[gegl/wip/pippin/pipeline: 878/880] gegl: add pipeline for point operations
- From: Øyvind "pippin" Kolås <ok src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gegl/wip/pippin/pipeline: 878/880] gegl: add pipeline for point operations
- Date: Thu, 20 Feb 2020 11:11:07 +0000 (UTC)
commit c1027b95316e10da4c44ecb74c423b93487ea352
Author: Øyvind Kolås <pippin gimp org>
Date: Mon Oct 8 20:15:07 2018 +0200
gegl: add pipeline for point operations
gegl/graph/gegl-node-private.h | 11 +
gegl/graph/gegl-node.c | 98 ++++-
gegl/graph/gegl-node.h | 6 +
gegl/operation/gegl-operation-context-private.h | 3 +-
gegl/operation/gegl-operation-context.c | 13 +
gegl/operation/gegl-operation-context.h | 7 +
gegl/operation/gegl-operation-pipeline.c | 563 ++++++++++++++++++++++++
gegl/operation/gegl-operation-pipeline.h | 46 ++
gegl/operation/gegl-operation-point-composer.c | 63 ++-
gegl/operation/gegl-operation-point-composer3.c | 59 ++-
gegl/operation/gegl-operation-point-filter.c | 77 +++-
gegl/operation/gegl-operation-point-render.c | 2 +-
gegl/operation/gegl-operation.c | 36 ++
gegl/operation/gegl-operation.h | 3 +
14 files changed, 944 insertions(+), 43 deletions(-)
---
diff --git a/gegl/graph/gegl-node-private.h b/gegl/graph/gegl-node-private.h
index 21d127dd7..2cb38866a 100644
--- a/gegl/graph/gegl-node-private.h
+++ b/gegl/graph/gegl-node-private.h
@@ -148,6 +148,17 @@ gegl_node_emit_computed (GeglNode *node,
const GeglRectangle *rect);
+struct _GeglNodePrivate
+{
+ GSList *source_connections;
+ GSList *sink_connections;
+ GSList *children; /* used for children */
+ GeglNode *parent;
+ gchar *name;
+ gchar *debug_name;
+ GeglEvalManager *eval_manager;
+};
+
G_END_DECLS
#endif /* __GEGL_NODE_PRIVATE_H__ */
diff --git a/gegl/graph/gegl-node.c b/gegl/graph/gegl-node.c
index 82e275eb9..964dd3752 100644
--- a/gegl/graph/gegl-node.c
+++ b/gegl/graph/gegl-node.c
@@ -69,16 +69,6 @@ enum
};
-struct _GeglNodePrivate
-{
- GSList *source_connections;
- GSList *sink_connections;
- GSList *children; /* used for children */
- GeglNode *parent;
- gchar *name;
- gchar *debug_name;
- GeglEvalManager *eval_manager;
-};
static guint gegl_node_signals[LAST_SIGNAL] = {0};
@@ -2421,3 +2411,91 @@ const char *gegl_operation_get_op_version (const char *op_name)
return ret;
}
+gint
+gegl_node_get_consumers2 (GeglNode *node,
+ const gchar *output_pad,
+ GeglNode ***nodes,
+ const gchar ***pads)
+{
+ GSList *connections;
+ gint n_connections;
+ GeglPad *pad;
+ gchar **pasp = NULL;
+
+ g_return_val_if_fail (output_pad != NULL, 0);
+
+ if(node->is_graph)
+ node = gegl_node_get_input_proxy(node, "input");
+
+ g_return_val_if_fail (GEGL_IS_NODE (node), 0);
+
+ pad = gegl_node_get_pad (node, output_pad);
+
+ if (!pad)
+ {
+ g_warning ("%s: no such pad %s for %s",
+ G_STRFUNC, output_pad, gegl_node_get_debug_name (node));
+ return 0;
+ }
+
+ connections = gegl_pad_get_connections (pad);
+ {
+ GSList *iter;
+ gint pasp_size = 0;
+ gint i;
+ gint pasp_pos = 0;
+
+ n_connections = g_slist_length (connections);
+ pasp_size += (n_connections + 1) * sizeof (gchar *);
+
+ for (iter = connections; iter; iter = g_slist_next (iter))
+ {
+ GeglConnection *connection = iter->data;
+ GeglPad *pad = gegl_connection_get_sink_pad (connection);
+ pasp_size += strlen (gegl_pad_get_name (pad)) + 1;
+ }
+ if (nodes)
+ *nodes = g_malloc ((n_connections + 1) * sizeof (void *));
+ if (pads)
+ {
+ pasp = g_malloc (pasp_size);
+ *pads = (void *) pasp;
+ }
+ i = 0;
+ pasp_pos = (n_connections + 1) * sizeof (void *);
+ for (iter = connections; iter; iter = g_slist_next (iter))
+ {
+ GeglConnection *connection = iter->data;
+ GeglPad *pad = gegl_connection_get_sink_pad (connection);
+ GeglNode *node = gegl_connection_get_sink_node (connection);
+ const gchar *pad_name = gegl_pad_get_name (pad);
+ const gchar *name = gegl_node_get_name(node);
+
+ gchar* proxy_name = g_strconcat("proxynop-", pad_name, NULL);
+ if(!strcmp(name, proxy_name))
+ {
+ node = g_object_get_data(G_OBJECT(node), "graph");
+ name = gegl_node_get_name(node);
+ }
+ else
+ {
+ }
+ g_free (proxy_name);
+
+ if (nodes)
+ (*nodes)[i] = node;
+ if (pasp)
+ {
+ pasp[i] = ((gchar *) pasp) + pasp_pos;
+ strcpy (pasp[i], pad_name);
+ }
+ pasp_pos += strlen (pad_name) + 1;
+ i++;
+ }
+ if (nodes)
+ (*nodes)[i] = NULL;
+ if (pads)
+ pasp[i] = NULL;
+ }
+ return n_connections;
+}
diff --git a/gegl/graph/gegl-node.h b/gegl/graph/gegl-node.h
index 6eca2cfb9..6df8135ab 100644
--- a/gegl/graph/gegl-node.h
+++ b/gegl/graph/gegl-node.h
@@ -693,6 +693,12 @@ void gegl_node_set_passthrough (GeglNode *node,
gboolean gegl_node_is_graph (GeglNode *node);
+gint
+gegl_node_get_consumers2 (GeglNode *node,
+ const gchar *output_pad,
+ GeglNode ***nodes,
+ const gchar ***pads);
+
void gegl_node_progress (GeglNode *node, gdouble progress, gchar *message);
const char *gegl_operation_get_op_version (const gchar *op_name);
diff --git a/gegl/operation/gegl-operation-context-private.h b/gegl/operation/gegl-operation-context-private.h
index b624c4756..bf7149233 100644
--- a/gegl/operation/gegl-operation-context-private.h
+++ b/gegl/operation/gegl-operation-context-private.h
@@ -23,7 +23,6 @@
G_BEGIN_DECLS
-#include "gegl-operation.h"
/**
* When a node in a GEGL graph does processing, it needs context such
@@ -61,6 +60,8 @@ struct _GeglOperationContext
2 = 1:4,
4 = 1:8,
6 = 1:16 .. */
+ GeglOperationPipeLine *pipeline;
+
GHashTable *contexts; /* to be able to look up the context of
other nodes/ops in the graph we store the
hashtable we will be stored in */
diff --git a/gegl/operation/gegl-operation-context.c b/gegl/operation/gegl-operation-context.c
index a70a5ee8b..3fda0a662 100644
--- a/gegl/operation/gegl-operation-context.c
+++ b/gegl/operation/gegl-operation-context.c
@@ -414,6 +414,19 @@ gegl_operation_context_node_get_context (GeglOperationContext *context,
}
+GeglOperationPipeLine *gegl_operation_context_get_pipeline (GeglOperationContext *context)
+{
+ if (!context) return NULL;
+ return context->pipeline;
+}
+void gegl_operation_context_set_pipeline (GeglOperationContext *context,
+ GeglOperationPipeLine *pipeline)
+{
+ if (!context) return;
+ context->pipeline = pipeline;
+}
+
+
GeglBuffer *
gegl_operation_context_dup_input_maybe_copy (GeglOperationContext *context,
const gchar *padname,
diff --git a/gegl/operation/gegl-operation-context.h b/gegl/operation/gegl-operation-context.h
index 53af4736e..658c2d038 100644
--- a/gegl/operation/gegl-operation-context.h
+++ b/gegl/operation/gegl-operation-context.h
@@ -23,6 +23,8 @@
G_BEGIN_DECLS
+typedef struct _GeglOperationPipeLine GeglOperationPipeLine;
+
GeglBuffer *gegl_operation_context_get_target (GeglOperationContext *self,
const gchar *padname);
GeglBuffer *gegl_operation_context_get_source (GeglOperationContext *self,
@@ -57,6 +59,11 @@ GeglBuffer * gegl_operation_context_dup_input_maybe_copy (GeglOperationC
GeglOperationContext *gegl_operation_context_node_get_context (GeglOperationContext *context,
GeglNode *node);
+GeglOperationPipeLine *gegl_operation_context_get_pipeline (GeglOperationContext *context);
+
+void gegl_operation_context_set_pipeline (GeglOperationContext *context,
+ GeglOperationPipeLine *pipeline);
+
G_END_DECLS
diff --git a/gegl/operation/gegl-operation-pipeline.c b/gegl/operation/gegl-operation-pipeline.c
new file mode 100644
index 000000000..86e3d967d
--- /dev/null
+++ b/gegl/operation/gegl-operation-pipeline.c
@@ -0,0 +1,563 @@
+#include "config.h"
+
+#include <glib-object.h>
+#define GEGL_ITERATOR2_API // opt in to new buffer iterator API
+
+#include "gegl.h"
+#include "gegl-debug.h"
+#include "gegl-operation-point-filter.h"
+#include "gegl-operation-point-composer.h"
+#include "gegl-operation-point-composer3.h"
+#include "gegl-operation-context.h"
+#include "gegl-operation-pipeline.h"
+#include "gegl-config.h"
+#include "gegl-types-internal.h"
+#include "gegl-buffer-private.h"
+#include "gegl-tile-storage.h"
+#include <gegl-node-private.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+
+#define PIPELINE_MAX 64
+
+typedef struct {
+ GeglOperation *operation;
+ int in_pads;
+ void (*process)(void *);
+ GeglBuffer *aux;
+ GeglBuffer *aux2;
+ int aux_handle; /* these values are deterministic */
+ int aux2_handle; /* and can scarily be shared among processes */
+ const Babl *input_fish;
+ const Babl *in_format;
+ const Babl *aux_format;
+ const Babl *aux2_format;
+ const Babl *out_format;
+} PipeEntry;
+
+
+/* first make it work for a filter op masking its own output as
+ * a single entry pipeline
+ *
+ * then generalize/expand
+ */
+
+
+struct _GeglOperationPipeLine {
+ int entries;
+ GeglBuffer *input;
+ int buffers_used;
+ PipeEntry entry[PIPELINE_MAX];
+};
+
+/* returns true if the passed op could be part of a pipeline
+ */
+gboolean gegl_operation_is_pipelinable (GeglOperation *op)
+{
+ gboolean ret = GEGL_IS_OPERATION_POINT_FILTER (op) ||
+ GEGL_IS_OPERATION_POINT_COMPOSER (op) ||
+ GEGL_IS_OPERATION_POINT_COMPOSER3 (op);
+ if (ret)
+ {
+ GeglOperationClass *op_klass = GEGL_OPERATION_GET_CLASS (op);
+ if (op_klass->want_in_place == FALSE)
+ return FALSE;
+ }
+ if (0 && ret)
+ {
+ const char *name = gegl_operation_get_name (op);
+ if (!strcmp (name, "gimp:mask-components"))
+ return FALSE;
+ }
+ return ret;
+}
+
+static GeglNode *gegl_node_get_non_nop_producer (GeglNode *n)
+{
+ GeglNode *node = gegl_operation_get_source_node (n->operation, "input");
+ gint n_consumers;
+ fprintf (stderr, "%s.\n", gegl_node_get_operation (n));
+ n_consumers = gegl_node_get_consumers (node, "output", NULL, NULL);
+ fprintf (stderr, ".%s %i.\n", node?gegl_node_get_operation (node):"-", n_consumers);
+ while (node &&
+ (!strcmp (gegl_node_get_operation (node), "gegl:nop") ||
+ !strcmp (gegl_node_get_operation (node), "GraphNode"))
+ && (n_consumers == 1 /*|| n_consumers ==2*/) && !
+ node->priv->eval_manager)
+ {
+ node = gegl_operation_get_source_node (node->operation, "input");
+ n_consumers = gegl_node_get_consumers (node, "output", NULL, NULL);
+ }
+ if (n_consumers != 1 /*||n_consumers == 2*/)
+ node = NULL;
+ fprintf (stderr, "..%s %i\n", node?gegl_node_get_operation (node):"-", n_consumers);
+ return node;
+}
+
+GeglOperationPipeLine *
+gegl_operation_pipeline_ensure (GeglOperation *operation,
+ GeglOperationContext *context,
+ GeglBuffer *input)
+{
+ GeglOperationPipeLine *pipeline = NULL;
+ GeglNode *source_node;
+ GeglOperationContext *source_context;
+ source_node = gegl_node_get_non_nop_producer (operation->node);
+ if (source_node && !source_node->priv->eval_manager)
+ {
+ source_context = gegl_operation_context_node_get_context (context, source_node);
+ pipeline = gegl_operation_context_get_pipeline (source_context);
+ gegl_operation_context_set_pipeline (source_context, NULL);
+ }
+
+ if (!pipeline)
+ {
+ pipeline = g_malloc0 (sizeof (GeglOperationPipeLine));
+ pipeline->buffers_used = 2; // input and output
+ }
+ gegl_operation_context_set_pipeline (context, pipeline);
+
+ if (gegl_operation_pipeline_get_entries (pipeline) == 0)
+ gegl_operation_pipeline_set_input (pipeline, input);
+
+ return pipeline;
+}
+
+
+/* we should not be intermediate if adding more bits to the pipeline
+ would not work
+ */
+gboolean
+gegl_operation_pipeline_is_intermediate_node (GeglOperation *op,
+ GeglOperationPipeLine *pipeline)
+{
+ gboolean is_intermediate = TRUE;
+ gint n_consumers;
+ GeglNode *it = op->node;
+ GeglNode **consumers = NULL;
+
+ fprintf (stderr, "[%s\n", gegl_operation_get_name (op));
+ if (op->node->priv->eval_manager)
+ {
+ fprintf (stderr, "chaughta a fraggel!\n");
+ return FALSE;
+ }
+
+ n_consumers = gegl_node_get_consumers2 (it, "output", &consumers, NULL);
+
+ if (n_consumers == 0)
+ {
+ fprintf (stderr, "[[--\n");
+ is_intermediate = FALSE;
+ }
+
+ it = consumers[0];
+#if 1
+ while ((n_consumers == 1 /* || n_consumers==2*/)&&
+ (!strcmp (gegl_node_get_operation (consumers[0]), "gegl:nop")||
+ !strcmp (gegl_node_get_operation (consumers[0]), "GraphNode")))
+ {
+ it = consumers[0];
+ g_free (consumers);
+ n_consumers = gegl_node_get_consumers2 (it, "output", &consumers, NULL);
+ }
+#endif
+
+ if (n_consumers == 0 && it != op->node)
+ {
+ return TRUE;
+ }
+ else if (n_consumers == 1)
+ {
+ GeglOperation *sink = gegl_node_get_gegl_operation (consumers[0]);
+
+ if (! gegl_operation_is_pipelinable (sink))
+ is_intermediate = FALSE;
+ else if (pipeline->entries + 1 >= PIPELINE_MAX)
+ is_intermediate = FALSE;
+ else
+ is_intermediate = TRUE;
+ fprintf (stderr, "[[%s %s\n", gegl_operation_get_name (sink), is_intermediate?"pipelineable":"not
pipelineable");
+ }
+ else
+ {
+ is_intermediate = FALSE;
+ fprintf (stderr, "[%s=--%i-\n",
+ gegl_operation_get_name (consumers[0]->operation), n_consumers);
+ }
+
+ g_free (consumers);
+
+ return is_intermediate;
+}
+
+static gboolean
+_gegl_operation_pipeline_process (GeglOperationPipeLine *pipeline,
+ GeglBuffer *output,
+ const GeglRectangle *result,
+ gint level)
+{
+ GeglBufferIterator *i = gegl_buffer_iterator_new (output, result, level,
pipeline->entry[pipeline->entries-1].out_format,
+ GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE,
pipeline->buffers_used+1);
+ gint input_handle = 0;
+ void *temp[2]={NULL, NULL};
+ glong high_tide = 0;
+ void *cur_input = NULL;
+ void *cur_output = NULL;
+ int buf_mod = 0;
+
+ if (pipeline->input)
+ input_handle = gegl_buffer_iterator_add (i, pipeline->input, result, level,
+ pipeline->entry[0].in_format,
+ GEGL_ACCESS_READ, GEGL_ABYSS_NONE);
+
+ {
+ gint e;
+ for (e = 0; e < pipeline->entries; e++)
+ {
+ PipeEntry *entry = &pipeline->entry[e];
+ switch (pipeline->entry[e].in_pads)
+ {
+ case 3:
+ if (entry->aux2)
+ entry->aux2_handle =
+ gegl_buffer_iterator_add (i, entry->aux2, result, level,
+ entry->aux2_format,
+ GEGL_ACCESS_READ, GEGL_ABYSS_NONE);
+ case 2:
+ if (entry->aux)
+ entry->aux_handle =
+ gegl_buffer_iterator_add (i, entry->aux, result, level,
+ entry->aux_format,
+ GEGL_ACCESS_READ, GEGL_ABYSS_NONE);
+ case 1:
+ default:
+ break;
+ }
+ }
+ }
+
+ while (gegl_buffer_iterator_next (i))
+ {
+ gint e;
+ if (i->length > high_tide)
+ {
+ if (temp[0])
+ g_free (temp[0]);
+ high_tide = i->length;
+ temp[0] = g_malloc (4 * 8 * high_tide * 2);
+ temp[1] = (char*)(temp[0]) + 4 * 8 * high_tide;
+ /* the two allocations are merged into one, to reduce overhead,
+ if sufficiently small for the architecture - this could use
+ stack allocations
+ */
+ }
+
+ for (e = 0; e < pipeline->entries; e++)
+ {
+ PipeEntry *entry = &pipeline->entry[e];
+ if (e == 0)
+ {
+ if (pipeline->input)
+ cur_input = i->items[input_handle].data;
+ }
+ else
+ {
+ if (!entry->input_fish)
+ {
+ cur_input = cur_output;
+ }
+ else
+ {
+ cur_input = temp[(buf_mod++)&1];
+ babl_process (entry->input_fish,
+ cur_output, cur_input, i->length);
+
+ }
+ }
+ if (pipeline->entries == e+1)
+ {
+ cur_output = i->items[0].data;
+ }
+ else
+ {
+ if (entry->in_format == entry->out_format)
+ cur_output = cur_input;
+ else
+ cur_output = temp[(buf_mod++)&1];
+ }
+
+ switch (entry->in_pads)
+ {
+ case 0:
+ {
+ gboolean (*process)(GeglOperation *,
+ void *,
+ glong,
+ const GeglRectangle *,
+ gint) = (void*)entry->process;
+
+ process (entry->operation,
+ cur_output,
+ i->length,
+ &(i->items[0].roi),
+ level);
+ }break;
+ case 1:
+ {
+ gboolean (*process)(GeglOperation *,
+ void *,
+ void *,
+ glong,
+ const GeglRectangle *,
+ gint) = (void*)entry->process;
+
+ process (entry->operation,
+ cur_input,
+ cur_output,
+ i->length,
+ &(i->items[0].roi),
+ level);
+ }break;
+
+ case 2:
+ {
+ gboolean (*process)(GeglOperation *,
+ void *,
+ void *,
+ void *,
+ glong,
+ const GeglRectangle *,
+ gint) = (void*)entry->process;
+
+ process (entry->operation,
+ cur_input,
+ entry->aux?
+ i->items[entry->aux_handle].data:
+ NULL,
+ cur_output,
+ i->length,
+ &(i->items[0].roi),
+ level);
+ }break;
+
+ case 3:
+ {
+ gboolean (*process)(GeglOperation *,
+ void *,
+ void *,
+ void *,
+ void *,
+ glong,
+ const GeglRectangle *,
+ gint) = (void*)entry->process;
+ process (entry->operation,
+ cur_input,
+ entry->aux?
+ i->items[entry->aux_handle].data:
+ NULL,
+ entry->aux2?
+ i->items[entry->aux2_handle].data:
+ NULL,
+ cur_output,
+ i->length,
+ &(i->items[0].roi),
+ level);
+ }break;
+ }
+ }
+ }
+
+
+ if (temp[0])
+ g_free (temp[0]);
+
+ return TRUE;
+}
+
+void
+gegl_operation_pipeline_destroy (GeglOperationPipeLine *pipeline)
+{
+ g_clear_object (&pipeline->input);
+ {
+ gint e;
+ for (e = 0; e < pipeline->entries; e++)
+ {
+ PipeEntry *entry = &pipeline->entry[e];
+
+ switch (entry->in_pads)
+ {
+ case 3:
+ if (entry->aux2)
+ g_clear_object (&entry->aux2);
+ case 2:
+ if (entry->aux)
+ g_clear_object (&entry->aux);
+ case 1:
+ default:
+ break;
+ }
+ }
+ }
+
+ g_free (pipeline);
+}
+
+typedef struct ThreadData
+{
+ GeglOperationPipeLine *pipeline;
+ GeglBuffer *output;
+ gint *pending;
+ gint level;
+ GeglRectangle result;
+} ThreadData;
+
+static void thread_process (gpointer thread_data, gpointer unused)
+{
+ ThreadData *data = thread_data;
+ _gegl_operation_pipeline_process (data->pipeline, data->output, &data->result, data->level);
+ g_atomic_int_add (data->pending, -1);
+}
+
+static GThreadPool *thread_pool (void)
+{
+ static GThreadPool *pool = NULL;
+ if (!pool)
+ {
+ pool = g_thread_pool_new (thread_process, NULL, gegl_config_threads (),
+ FALSE, NULL);
+ }
+ return pool;
+}
+
+gboolean
+gegl_operation_pipeline_process (GeglOperationPipeLine *pipeline,
+ GeglBuffer *output,
+ const GeglRectangle *result,
+ gint level)
+{
+ gint threads = gegl_config_threads();
+
+ if (1) {
+ gint e;
+ fprintf (stderr, "{%i}", pipeline->entries);
+ for (e = 0; e < pipeline->entries; e++)
+ {
+ PipeEntry *entry = &pipeline->entry[e];
+ fprintf (stderr, "%s ", gegl_operation_get_name (entry->operation));
+ }
+ fprintf (stderr, "\n");
+ }
+
+ if (threads == 1 || result->width * result->height < 64*64 || result->height < threads)
+ {
+ return _gegl_operation_pipeline_process (pipeline, output, result, level);
+ }
+ else
+ {
+ ThreadData thread_data[threads];
+ GThreadPool *pool = thread_pool ();
+ gint pending;
+ gint j;
+ if (result->width > result->height)
+ for (j = 0; j < threads; j++)
+ {
+ GeglRectangle rect = *result;
+
+ rect.width /= threads;
+ rect.x += rect.width * j;
+
+ if (j == threads-1)
+ rect.width = (result->width + result->x) - rect.x;
+
+ thread_data[j].result = rect;
+ }
+ else
+ for (j = 0; j < threads; j++)
+ {
+ GeglRectangle rect = *result;
+
+ rect = *result;
+ rect.height /= threads;
+ rect.y += rect.height * j;
+
+ if (j == threads-1)
+ rect.height = (result->height + result->y) - rect.y;
+
+ thread_data[j].result = rect;
+ }
+ for (j = 0; j < threads; j++)
+ {
+ thread_data[j].output = output;
+ thread_data[j].pipeline = pipeline;
+ thread_data[j].pending = &pending;
+ thread_data[j].level = level;
+ }
+ pending = threads;
+
+ // XXX cl flushes?
+
+ for (gint j = 1; j < threads; j++)
+ g_thread_pool_push (pool, &thread_data[j], NULL);
+ thread_process (&thread_data[0], NULL);
+ while (g_atomic_int_get (&pending)) {};
+
+ return TRUE;
+ }
+}
+
+void
+gegl_operation_pipeline_add (GeglOperationPipeLine *pipeline,
+ GeglOperation *operation,
+ gint in_pads,
+ const Babl *in_format,
+ const Babl *out_format,
+ const Babl *aux_format,
+ const Babl *aux2_format,
+ GeglBuffer *aux,
+ GeglBuffer *aux2,
+ void *process)
+{
+ PipeEntry *entry;
+ PipeEntry *prev_entry;
+
+ g_assert (pipeline);
+ g_assert (pipeline->entries + 1 <= PIPELINE_MAX);
+
+ entry = &pipeline->entry[pipeline->entries];
+ prev_entry = pipeline->entries?&pipeline->entry[pipeline->entries-1]:NULL;
+
+ entry->operation = operation;
+ entry->in_pads = in_pads;
+ entry->in_format = in_format;
+ entry->aux_format = aux_format;
+ entry->aux = aux;
+ entry->aux2_format= aux2_format;
+ entry->aux2 = aux2;
+ entry->out_format = out_format;
+ entry->process = process;
+
+ if (prev_entry && entry->in_format != prev_entry->out_format)
+ {
+ entry->input_fish = babl_fish (prev_entry->out_format, entry->in_format);
+ }
+
+ pipeline->entries++;
+
+ pipeline->buffers_used += ( (aux?1:0) + (aux2?1:0));
+}
+
+int gegl_operation_pipeline_get_entries (GeglOperationPipeLine *pipeline)
+{
+ return pipeline->entries;
+}
+
+
+
+void gegl_operation_pipeline_set_input (GeglOperationPipeLine *pipeline,
+ GeglBuffer *buffer)
+{
+ pipeline->input = buffer;
+}
diff --git a/gegl/operation/gegl-operation-pipeline.h b/gegl/operation/gegl-operation-pipeline.h
new file mode 100644
index 000000000..9f0835c94
--- /dev/null
+++ b/gegl/operation/gegl-operation-pipeline.h
@@ -0,0 +1,46 @@
+#ifndef _GEGL_OPERATION_PIPELINE_H
+#define _GEGL_OPERATION_PIPELINE_H
+
+
+int gegl_operation_pipeline_get_entries (GeglOperationPipeLine *pipeline);
+void gegl_operation_pipeline_set_input (GeglOperationPipeLine *pipeline,
+ GeglBuffer *buffer);
+
+gboolean
+gegl_operation_pipeline_is_intermediate_node (GeglOperation *op,
+ GeglOperationPipeLine *pipeline);
+gboolean gegl_operation_pipeline_is_composite_node (GeglOperation *op);
+
+gboolean gegl_operation_pipeline_process (GeglOperationPipeLine *pipeline,
+ GeglBuffer *output,
+ const GeglRectangle *result,
+ gint level);
+GeglOperationPipeLine *
+gegl_operation_pipeline_ensure (GeglOperation *operation,
+ GeglOperationContext *context,
+ GeglBuffer *input);
+
+
+void
+gegl_operation_pipeline_add (GeglOperationPipeLine *pipeline,
+ GeglOperation *operation,
+ gint in_pads,
+ const Babl *in_format,
+ const Babl *out_format,
+ const Babl *aux_format,
+ const Babl *aux2_format,
+ GeglBuffer *aux,
+ GeglBuffer *aux2,
+ void *process);
+
+gboolean
+gegl_operation_pipeline_process_threaded (GeglOperationPipeLine *pipeline,
+ GeglBuffer *output,
+ const GeglRectangle *result,
+ gint level);
+
+gboolean gegl_operation_is_pipelinable (GeglOperation *op);
+void
+gegl_operation_pipeline_destroy (GeglOperationPipeLine *pipeline);
+
+#endif
diff --git a/gegl/operation/gegl-operation-point-composer.c b/gegl/operation/gegl-operation-point-composer.c
index e13f8b8ed..f76d763f3 100644
--- a/gegl/operation/gegl-operation-point-composer.c
+++ b/gegl/operation/gegl-operation-point-composer.c
@@ -17,15 +17,16 @@
*/
+#define GEGL_ITERATOR2_API
#include "config.h"
#include <glib-object.h>
-
#include "gegl.h"
#include "gegl-debug.h"
#include "gegl-operation-point-composer.h"
#include "gegl-operation-context.h"
+#include "gegl-operation-pipeline.h"
#include "gegl-config.h"
#include "gegl-types-internal.h"
#include "gegl-buffer-private.h"
@@ -64,8 +65,7 @@ thread_process (const GeglRectangle *area,
data->level,
data->output_format,
GEGL_ACCESS_WRITE,
- GEGL_ABYSS_NONE,
- 4);
+ GEGL_ABYSS_NONE, 3);
if (data->input)
read = gegl_buffer_iterator_add (i, data->input, area, data->level,
@@ -93,10 +93,12 @@ gegl_operation_composer_process (GeglOperation *operation,
gint level)
{
GeglOperationComposerClass *klass = GEGL_OPERATION_COMPOSER_GET_CLASS (operation);
+ GeglOperationPointComposerClass *point_composer_class = GEGL_OPERATION_POINT_COMPOSER_GET_CLASS
(operation);
GeglBuffer *input;
GeglBuffer *aux;
GeglBuffer *output;
gboolean success = FALSE;
+ GeglOperationPipeLine *pipeline;
GeglRectangle scaled_result = *result;
if (level)
@@ -121,13 +123,56 @@ gegl_operation_composer_process (GeglOperation *operation,
}
input = (GeglBuffer*) gegl_operation_context_dup_object (context, "input");
- output = gegl_operation_context_get_output_maybe_in_place (operation,
- context,
- input,
- result);
-
aux = (GeglBuffer*) gegl_operation_context_dup_object (context, "aux");
+ if (!input && !aux)
+ return FALSE;
+
+ if (gegl_operation_is_pipelinable (operation))
+ {
+ pipeline = gegl_operation_pipeline_ensure (operation, context, input);
+
+ gegl_operation_pipeline_add (pipeline, operation, 2,
+ gegl_operation_get_format (operation, "input"),
+ gegl_operation_get_format (operation, "output"),
+ gegl_operation_get_format (operation, "aux"),
+ NULL,
+ aux, NULL,
+ point_composer_class->process);
+
+ if (gegl_operation_pipeline_is_intermediate_node (operation, pipeline))
+ {
+ gegl_operation_context_take_object (context, "output", G_OBJECT (input));
+
+ return TRUE;
+ }
+
+ output = gegl_operation_context_get_output_maybe_in_place (operation,
+ context,
+ input,
+ result);
+
+ gegl_operation_context_set_pipeline (context, NULL);
+ if (gegl_operation_pipeline_get_entries (pipeline) > 1)
+ {
+ gegl_operation_pipeline_process (pipeline, output, result, level);
+ gegl_operation_pipeline_destroy (pipeline);
+ return TRUE;
+ }
+ g_object_ref (input);
+ if (aux)
+ g_object_ref (aux);
+ gegl_operation_pipeline_destroy (pipeline);
+
+ }
+ else
+ {
+ output = gegl_operation_context_get_output_maybe_in_place (operation,
+ context,
+ input,
+ result);
+ }
+
/* A composer with a NULL aux, can still be valid, the
* subclass has to handle it.
*/
@@ -338,7 +383,7 @@ gegl_operation_point_composer_process (GeglOperation *operation,
}
else
{
- GeglBufferIterator *i = gegl_buffer_iterator_new (output, result, level, out_format,
GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE, 4);
+ GeglBufferIterator *i = gegl_buffer_iterator_new (output, result, level, out_format,
GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE, 3);
gint foo = 0, read = 0;
if (input)
diff --git a/gegl/operation/gegl-operation-point-composer3.c b/gegl/operation/gegl-operation-point-composer3.c
index abf954d72..c6ee373cd 100644
--- a/gegl/operation/gegl-operation-point-composer3.c
+++ b/gegl/operation/gegl-operation-point-composer3.c
@@ -24,6 +24,7 @@
#include "gegl.h"
#include "gegl-operation-point-composer3.h"
#include "gegl-operation-context.h"
+#include "gegl-operation-pipeline.h"
#include "gegl-types-internal.h"
#include "gegl-config.h"
#include "gegl-buffer-private.h"
@@ -96,11 +97,13 @@ gegl_operation_composer3_process (GeglOperation *operation,
gint level)
{
GeglOperationComposer3Class *klass = GEGL_OPERATION_COMPOSER3_GET_CLASS (operation);
+ GeglOperationPointComposer3Class *point_composer3_class = GEGL_OPERATION_POINT_COMPOSER3_GET_CLASS
(operation);
GeglBuffer *input;
GeglBuffer *aux;
GeglBuffer *aux2;
GeglBuffer *output;
gboolean success = FALSE;
+ GeglOperationPipeLine *pipeline;
if (strcmp (output_prop, "output"))
{
@@ -115,13 +118,57 @@ gegl_operation_composer3_process (GeglOperation *operation,
}
input = (GeglBuffer*) gegl_operation_context_dup_object (context, "input");
- output = gegl_operation_context_get_output_maybe_in_place (operation,
- context,
- input,
- result);
-
aux = (GeglBuffer*) gegl_operation_context_dup_object (context, "aux");
- aux2 = (GeglBuffer*) gegl_operation_context_dup_object (context, "aux2");
+ aux2 = (GeglBuffer*) gegl_operation_context_dup_object (context, "aux2");
+
+ if (!input && !aux && !aux2)
+ return FALSE;
+
+ if (gegl_operation_is_pipelinable (operation))
+ {
+ pipeline = gegl_operation_pipeline_ensure (operation, context, input);
+
+ gegl_operation_pipeline_add (pipeline, operation, 3,
+ gegl_operation_get_format (operation, "input"),
+ gegl_operation_get_format (operation, "output"),
+ gegl_operation_get_format (operation, "aux"),
+ gegl_operation_get_format (operation, "aux2"),
+ aux, aux2,
+ point_composer3_class->process);
+
+ if (gegl_operation_pipeline_is_intermediate_node (operation, pipeline))
+ {
+ gegl_operation_context_take_object (context, "output", G_OBJECT (input));
+
+ return TRUE;
+ }
+
+ output = gegl_operation_context_get_output_maybe_in_place (operation,
+ context,
+ input,
+ result);
+ gegl_operation_context_set_pipeline (context, NULL);
+
+ if (gegl_operation_pipeline_get_entries (pipeline) > 1)
+ {
+ gegl_operation_pipeline_process (pipeline, output, result, level);
+ gegl_operation_pipeline_destroy (pipeline);
+ return TRUE;
+ }
+ g_object_ref (input);
+ if (aux)
+ g_object_ref (aux);
+ if (aux2)
+ g_object_ref (aux2);
+ gegl_operation_pipeline_destroy (pipeline);
+ }
+ else
+ {
+ output = gegl_operation_context_get_output_maybe_in_place (operation,
+ context,
+ input,
+ result);
+ }
/* A composer with a NULL aux, can still be valid, the
* subclass has to handle it.
diff --git a/gegl/operation/gegl-operation-point-filter.c b/gegl/operation/gegl-operation-point-filter.c
index 3197e5c83..d6f292745 100644
--- a/gegl/operation/gegl-operation-point-filter.c
+++ b/gegl/operation/gegl-operation-point-filter.c
@@ -25,6 +25,7 @@
#include "gegl-debug.h"
#include "gegl-operation-point-filter.h"
#include "gegl-operation-context.h"
+#include "gegl-operation-pipeline.h"
#include "gegl-config.h"
#include "gegl-types-internal.h"
#include "gegl-buffer-private.h"
@@ -58,7 +59,7 @@ thread_process (const GeglRectangle *area,
data->level,
data->output_format,
GEGL_ACCESS_WRITE,
- GEGL_ABYSS_NONE, 4);
+ GEGL_ABYSS_NONE, 2);
gint read = 0;
if (data->input)
read = gegl_buffer_iterator_add (i, data->input, area, data->level,
@@ -73,17 +74,20 @@ thread_process (const GeglRectangle *area,
}
}
+
static gboolean
gegl_operation_filter_process (GeglOperation *operation,
- GeglOperationContext *context,
- const gchar *output_prop,
- const GeglRectangle *result,
- gint level)
+ GeglOperationContext *context,
+ const gchar *output_prop,
+ const GeglRectangle *result,
+ gint level)
{
GeglOperationFilterClass *klass = GEGL_OPERATION_FILTER_GET_CLASS (operation);
+ GeglOperationPointFilterClass *point_filter_class = GEGL_OPERATION_POINT_FILTER_GET_CLASS (operation);
GeglBuffer *input;
GeglBuffer *output;
gboolean success = FALSE;
+ GeglOperationPipeLine *pipeline;
GeglRectangle scaled_result = *result;
if (level)
@@ -108,10 +112,51 @@ gegl_operation_filter_process (GeglOperation *operation,
}
input = (GeglBuffer*)gegl_operation_context_dup_object (context, "input");
- output = gegl_operation_context_get_output_maybe_in_place (operation,
- context,
- input,
- result);
+ if (!input)
+ {
+ return FALSE;
+ }
+
+
+ if (gegl_operation_is_pipelinable (operation))
+ {
+ pipeline = gegl_operation_pipeline_ensure (operation, context, input);
+
+ gegl_operation_pipeline_add (pipeline, operation, 1,
+ gegl_operation_get_format (operation, "input"),
+ gegl_operation_get_format (operation, "output"),
+ NULL, NULL, NULL, NULL, // auxes are not set
+ point_filter_class->process);
+
+ if (gegl_operation_pipeline_is_intermediate_node (operation, pipeline))
+ {
+ gegl_operation_context_take_object (context, "output", G_OBJECT (input));
+
+ return TRUE;
+ }
+
+ output = gegl_operation_context_get_output_maybe_in_place (operation,
+ context,
+ input,
+ result);
+
+ gegl_operation_context_set_pipeline (context, NULL);
+ if (gegl_operation_pipeline_get_entries (pipeline) > 1)
+ {
+ gegl_operation_pipeline_process (pipeline, output, result, level);
+ gegl_operation_pipeline_destroy (pipeline);
+ return TRUE;
+ }
+ g_object_ref (input);
+ gegl_operation_pipeline_destroy (pipeline);
+ }
+ else
+ {
+ output = gegl_operation_context_get_output_maybe_in_place (operation,
+ context,
+ input,
+ result);
+ }
if (input != NULL)
{
@@ -233,12 +278,13 @@ error:
static void
gegl_operation_point_filter_class_init (GeglOperationPointFilterClass *klass)
{
- GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
- GeglOperationFilterClass *filter_class = GEGL_OPERATION_FILTER_CLASS (klass);
+ GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
+ GeglOperationFilterClass *filter_class = GEGL_OPERATION_FILTER_CLASS (klass);
- filter_class->process = gegl_operation_point_filter_process;
- operation_class->process = gegl_operation_filter_process;
- operation_class->prepare = prepare;
+ filter_class->process = gegl_operation_point_filter_process;
+ operation_class->process = gegl_operation_filter_process;
+ operation_class->prepare = prepare;
+ operation_class->no_cache = TRUE;
operation_class->want_in_place = TRUE;
operation_class->threaded = TRUE;
}
@@ -261,7 +307,6 @@ gegl_operation_point_filter_process (GeglOperation *operation,
const Babl *in_format = gegl_operation_get_format (operation, "input");
const Babl *out_format = gegl_operation_get_format (operation, "output");
-
if ((result->width > 0) && (result->height > 0))
{
if (gegl_operation_use_opencl (operation) && (operation_class->cl_data ||
point_filter_class->cl_process))
@@ -297,7 +342,7 @@ gegl_operation_point_filter_process (GeglOperation *operation,
else
{
GeglBufferIterator *i = gegl_buffer_iterator_new (output, result, level, out_format,
- GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE, 4);
+ GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE, 2);
gint read = 0;
if (input)
diff --git a/gegl/operation/gegl-operation-point-render.c b/gegl/operation/gegl-operation-point-render.c
index 5060d022f..0a8ac37ba 100644
--- a/gegl/operation/gegl-operation-point-render.c
+++ b/gegl/operation/gegl-operation-point-render.c
@@ -99,7 +99,7 @@ gegl_operation_point_render_process (GeglOperation *operation,
if ((result->width > 0) && (result->height > 0))
{
GeglBufferIterator *i = gegl_buffer_iterator_new (output, result, level, out_format,
- GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE, 2);
+ GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE, 1);
while (gegl_buffer_iterator_next (i))
point_render_class->process (operation, i->items[0].data, i->length, &i->items[0].roi, level);
diff --git a/gegl/operation/gegl-operation.c b/gegl/operation/gegl-operation.c
index 39e6ba6e3..3c2a3c6bd 100644
--- a/gegl/operation/gegl-operation.c
+++ b/gegl/operation/gegl-operation.c
@@ -392,6 +392,42 @@ gegl_operation_get_source_node (GeglOperation *operation,
return gegl_pad_get_node (pad);
}
+GeglNode *
+gegl_operation_get_target_node (GeglOperation *operation,
+ const gchar *output_pad_name)
+{
+ GeglNode *node;
+ GeglPad *pad;
+
+ g_return_val_if_fail (GEGL_IS_OPERATION (operation), NULL);
+ g_return_val_if_fail (GEGL_IS_NODE (operation->node), NULL);
+ g_return_val_if_fail (output_pad_name != NULL, NULL);
+
+ node = operation->node;
+#if 0
+ if (node->is_graph)
+ {
+ node = gegl_node_get_output_proxy (node, output_pad_name);
+ output_pad_name = "input";
+ }
+#endif
+
+ pad = gegl_node_get_pad (node, output_pad_name);
+
+ if (!pad)
+ return NULL;
+
+ pad = gegl_pad_get_connected_to (pad);
+
+ if (!pad)
+ return NULL;
+
+ g_assert (gegl_pad_get_node (pad));
+
+ return gegl_pad_get_node (pad);
+}
+
+
GeglRectangle *
gegl_operation_source_get_bounding_box (GeglOperation *operation,
const gchar *input_pad_name)
diff --git a/gegl/operation/gegl-operation.h b/gegl/operation/gegl-operation.h
index 12d3bc62b..e1139ab63 100644
--- a/gegl/operation/gegl-operation.h
+++ b/gegl/operation/gegl-operation.h
@@ -303,6 +303,9 @@ void gegl_operation_progress (GeglOperation *operation, gdouble progress,
const Babl *gegl_operation_get_source_space (GeglOperation *operation, const char *in_pad);
+GeglNode *
+gegl_operation_get_target_node (GeglOperation *operation,
+ const gchar *output_pad_name);
G_END_DECLS
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]