[gegl] point-filter,-composer,-composer3: add threading logic
- From: Øyvind Kolås <ok src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gegl] point-filter,-composer,-composer3: add threading logic
- Date: Tue, 1 Jul 2014 00:09:03 +0000 (UTC)
commit a206f032f77064cf9bff8590ac83ca5b086b53fd
Author: Øyvind Kolås <pippin gimp org>
Date: Tue Jul 1 01:20:15 2014 +0200
point-filter,-composer,-composer3: add threading logic
When consuming chunks of gegl_buffer_iterate, moving the babl conversions from
the main thread to the work-threads is neccesary to barely cancel out overhead
on an i5.
gegl/operation/gegl-operation-point-composer.c | 387 +++++++++++++++--------
gegl/operation/gegl-operation-point-composer3.c | 338 ++++++++++++++++++--
gegl/operation/gegl-operation-point-filter.c | 328 +++++++++++++------
gegl/operation/gegl-operation-point-render.c | 1 +
4 files changed, 789 insertions(+), 265 deletions(-)
---
diff --git a/gegl/operation/gegl-operation-point-composer.c b/gegl/operation/gegl-operation-point-composer.c
index b3c11e8..d311507 100644
--- a/gegl/operation/gegl-operation-point-composer.c
+++ b/gegl/operation/gegl-operation-point-composer.c
@@ -22,13 +22,141 @@
#include <glib-object.h>
#include "gegl.h"
-#include "gegl/gegl-debug.h"
#include "gegl-operation-point-composer.h"
#include "gegl-operation-context.h"
+#include "gegl-config.h"
+#include <sys/types.h>
+#include <unistd.h>
#include <string.h>
-#include "opencl/gegl-cl.h"
-#include "gegl-buffer-cl-iterator.h"
+typedef struct ThreadData
+{
+ GeglOperationPointComposerClass *klass;
+ GeglOperation *operation;
+ guchar *input;
+ guchar *aux;
+ guchar *output;
+ gint *pending;
+ gint *started;
+ gint level;
+ gboolean success;
+ GeglRectangle roi;
+
+ guchar *in_tmp;
+ guchar *aux_tmp;
+ guchar *output_tmp;
+ const Babl *input_fish;
+ const Babl *aux_fish;
+ const Babl *output_fish;
+} ThreadData;
+
+static void thread_process (gpointer thread_data, gpointer unused)
+{
+ ThreadData *data = thread_data;
+
+ guchar *input = data->input;
+ guchar *aux = data->aux;
+ guchar *output = data->output;
+ glong samples = data->roi.width * data->roi.height;
+
+ if (data->input_fish && input)
+ {
+ babl_process (data->input_fish, data->input, data->in_tmp, samples);
+ input = data->in_tmp;
+ }
+ if (data->aux_fish && aux)
+ {
+ babl_process (data->aux_fish, data->aux, data->aux_tmp, samples);
+ aux = data->aux_tmp;
+ }
+ if (data->output_fish)
+ output = data->output_tmp;
+
+ if (!data->klass->process (data->operation,
+ input, aux,
+ output, samples,
+ &data->roi, data->level))
+ data->success = FALSE;
+
+ if (data->output_fish)
+ babl_process (data->output_fish, data->output_tmp, data->output, samples);
+
+ 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;
+}
+
+static gboolean
+gegl_operation_composer_process (GeglOperation *operation,
+ GeglOperationContext *context,
+ const gchar *output_prop,
+ const GeglRectangle *result,
+ gint level)
+{
+ GeglOperationComposerClass *klass = GEGL_OPERATION_COMPOSER_GET_CLASS (operation);
+ GeglOperationClass *op_class = GEGL_OPERATION_CLASS (klass);
+ GeglBuffer *input;
+ GeglBuffer *aux;
+ GeglBuffer *output;
+ gboolean success = FALSE;
+
+ if (strcmp (output_prop, "output"))
+ {
+ g_warning ("requested processing of %s pad on a composer", output_prop);
+ return FALSE;
+ }
+
+ if (result->width == 0 || result->height == 0)
+ {
+ output = gegl_operation_context_get_target (context, "output");
+ return TRUE;
+ }
+
+ input = gegl_operation_context_get_source (context, "input");
+
+ if (op_class->want_in_place &&
+ gegl_can_do_inplace_processing (operation, input, result))
+ {
+ output = g_object_ref (input);
+ gegl_operation_context_take_object (context, "output", G_OBJECT (output));
+ }
+ else
+ {
+ output = gegl_operation_context_get_target (context, "output");
+ }
+
+ aux = gegl_operation_context_get_source (context, "aux");
+
+ /* A composer with a NULL aux, can still be valid, the
+ * subclass has to handle it.
+ */
+ if (input != NULL ||
+ aux != NULL)
+ {
+ success = klass->process (operation, input, aux, output, result, level);
+
+ if (input)
+ g_object_unref (input);
+ if (aux)
+ g_object_unref (aux);
+ }
+ else
+ {
+ g_warning ("%s received NULL input, aux, and aux2",
+ gegl_node_get_operation (operation->node));
+ }
+
+ return success;
+}
static gboolean gegl_operation_point_composer_process
(GeglOperation *operation,
@@ -51,17 +179,15 @@ static void prepare (GeglOperation *operation)
static void
gegl_operation_point_composer_class_init (GeglOperationPointComposerClass *klass)
{
- /*GObjectClass *object_class = G_OBJECT_CLASS (klass);*/
- GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
- GeglOperationComposerClass *composer_class = GEGL_OPERATION_COMPOSER_CLASS (klass);
+ GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
+ GeglOperationComposerClass *composer_class = GEGL_OPERATION_COMPOSER_CLASS (klass);
composer_class->process = gegl_operation_point_composer_process;
+ operation_class->process = gegl_operation_composer_process;
operation_class->prepare = prepare;
- operation_class->no_cache = FALSE;
+ operation_class->no_cache =TRUE;
operation_class->want_in_place = TRUE;
-
- klass->process = NULL;
- klass->cl_process = NULL;
+ operation_class->threaded = TRUE;
}
static void
@@ -71,152 +197,159 @@ gegl_operation_point_composer_init (GeglOperationPointComposer *self)
}
static gboolean
-gegl_operation_point_composer_cl_process (GeglOperation *operation,
- GeglBuffer *input,
- GeglBuffer *aux,
- GeglBuffer *output,
- const GeglRectangle *result,
- gint level)
+gegl_operation_point_composer_process (GeglOperation *operation,
+ GeglBuffer *input,
+ GeglBuffer *aux,
+ GeglBuffer *output,
+ const GeglRectangle *result,
+ gint level)
{
- const Babl *in_format = gegl_operation_get_format (operation, "input");
- const Babl *aux_format = gegl_operation_get_format (operation, "aux");
- const Babl *out_format = gegl_operation_get_format (operation, "output");
-
- GeglOperationClass *operation_class = GEGL_OPERATION_GET_CLASS (operation);
GeglOperationPointComposerClass *point_composer_class = GEGL_OPERATION_POINT_COMPOSER_GET_CLASS
(operation);
+ const Babl *in_format = gegl_operation_get_format (operation, "input");
+ const Babl *aux_format = gegl_operation_get_format (operation, "aux");
+ const Babl *out_format = gegl_operation_get_format (operation, "output");
- cl_int cl_err = 0;
- gboolean err;
-
- gint foo, read;
- GeglBufferClIterator *i;
-
- /* non-texturizable format! */
- if (!gegl_cl_color_babl (in_format, NULL) ||
- !gegl_cl_color_babl (aux_format, NULL) ||
- !gegl_cl_color_babl (out_format, NULL))
- {
- GEGL_NOTE (GEGL_DEBUG_OPENCL, "Non-texturizable format!");
- return FALSE;
- }
-
- GEGL_NOTE (GEGL_DEBUG_OPENCL, "GEGL_OPERATION_POINT_COMPOSER: %s", operation_class->name);
-
- i = gegl_buffer_cl_iterator_new (output, result, out_format, GEGL_CL_BUFFER_WRITE);
- read = gegl_buffer_cl_iterator_add (i, input, result, in_format, GEGL_CL_BUFFER_READ, GEGL_ABYSS_NONE);
-
- if (aux)
- foo = gegl_buffer_cl_iterator_add (i, aux, result, aux_format, GEGL_CL_BUFFER_READ, GEGL_ABYSS_NONE);
-
- while (gegl_buffer_cl_iterator_next (i, &err))
+ if ((result->width > 0) && (result->height > 0))
{
- if (err) return FALSE;
+ const Babl *in_buf_format = input?gegl_buffer_get_format(input):NULL;
+ const Babl *aux_buf_format = aux?gegl_buffer_get_format(aux):NULL;
+ const Babl *output_buf_format = output?gegl_buffer_get_format(output):NULL;
+ if (gegl_operation_use_threading (operation, result) && result->height > 1)
+ {
+ gint threads = gegl_config ()->threads;
+ GThreadPool *pool = thread_pool ();
+ ThreadData thread_data[GEGL_MAX_THREADS];
+ GeglBufferIterator *i = gegl_buffer_iterator_new (output, result, level, output_buf_format,
GEGL_BUFFER_WRITE, GEGL_ABYSS_NONE);
+ gint foo = 0, read = 0;
+
+ gint in_bpp = input?babl_format_get_bytes_per_pixel (in_format):0;
+ gint aux_bpp = aux?babl_format_get_bytes_per_pixel (aux_format):0;
+ gint out_bpp = babl_format_get_bytes_per_pixel (out_format);
+
+ gint in_buf_bpp = input?babl_format_get_bytes_per_pixel (in_buf_format):0;
+ gint aux_buf_bpp = aux?babl_format_get_bytes_per_pixel (aux_buf_format):0;
+ gint out_buf_bpp = babl_format_get_bytes_per_pixel (output_buf_format);
+ gint temp_id = 0;
+
+ if (input)
+ {
+ read = gegl_buffer_iterator_add (i, input, result, level, in_buf_format, GEGL_BUFFER_READ,
GEGL_ABYSS_NONE);
+ for (gint j = 0; j < threads; j ++)
+ {
+ if (in_buf_format != in_format)
+ {
+ thread_data[j].input_fish = babl_fish (in_buf_format, in_format);
+ thread_data[j].in_tmp = gegl_temp_buffer (temp_id++, in_bpp * result->width * result->height);
+ }
+ else
+ {
+ thread_data[j].input_fish = NULL;
+ }
+ }
+ }
+ else
+ for (gint j = 0; j < threads; j ++)
+ thread_data[j].input_fish = NULL;
+ if (aux)
{
- if (point_composer_class->cl_process)
+ foo = gegl_buffer_iterator_add (i, aux, result, level, aux_buf_format, GEGL_BUFFER_READ,
GEGL_ABYSS_NONE);
+ for (gint j = 0; j < threads; j ++)
+ {
+ if (aux_buf_format != aux_format)
{
- err = point_composer_class->cl_process(operation, i->tex[read],
- (aux)? i->tex[foo] : NULL,
- i->tex[0], i->size[0], &i->roi[0], level);
- if (err)
- {
- gegl_buffer_cl_iterator_stop (i);
- GEGL_NOTE (GEGL_DEBUG_OPENCL, "Error: %s", operation_class->name);
- return FALSE;
- }
+ thread_data[j].aux_fish = babl_fish (aux_buf_format, aux_format);
+ thread_data[j].aux_tmp = gegl_temp_buffer (temp_id++, aux_bpp * result->width *
result->height);
}
- else if (operation_class->cl_data)
+ else
{
- gint p = 0;
- GeglClRunData *cl_data = operation_class->cl_data;
+ thread_data[j].aux_fish = NULL;
+ }
+ }
+ }
+ else
+ {
+ for (gint j = 0; j < threads; j ++)
+ thread_data[j].aux_fish = NULL;
+ }
- cl_err = gegl_clSetKernelArg(cl_data->kernel[0], p++, sizeof(cl_mem), (void*)&i->tex[read]);
- CL_CHECK;
+ for (gint j = 0; j < threads; j ++)
+ {
+ if (output_buf_format != gegl_buffer_get_format (output))
+ {
+ thread_data[j].output_fish = babl_fish (out_format, output_buf_format);
+ thread_data[j].output_tmp = gegl_temp_buffer (temp_id++, out_bpp * result->width *
result->height);
+ }
+ else
+ {
+ thread_data[j].output_fish = NULL;
+ }
+ }
- if (aux)
- cl_err = gegl_clSetKernelArg(cl_data->kernel[0], p++, sizeof(cl_mem), (void*)&i->tex[foo]);
- else
- cl_err = gegl_clSetKernelArg(cl_data->kernel[0], p++, sizeof(cl_mem), NULL);
- CL_CHECK;
+ while (gegl_buffer_iterator_next (i))
+ {
+ gint threads = gegl_config()->threads;
+ gint pending;
+ gint bit;
- cl_err = gegl_clSetKernelArg(cl_data->kernel[0], p++, sizeof(cl_mem), (void*)&i->tex[0]);
- CL_CHECK;
+ if (i->roi[0].height < threads)
+ {
+ threads = i->roi[0].height;
+ }
- gegl_operation_cl_set_kernel_args (operation, cl_data->kernel[0], &p, &cl_err);
- CL_CHECK;
+ bit = i->roi[0].height / threads;
+ pending = threads;
- cl_err = gegl_clEnqueueNDRangeKernel(gegl_cl_get_command_queue (),
- cl_data->kernel[0], 1,
- NULL, &i->size[0], NULL,
- 0, NULL, NULL);
- CL_CHECK;
+ for (gint j = 0; j < threads; j++)
+ {
+ thread_data[j].roi.x = (i->roi[0]).x;
+ thread_data[j].roi.width = (i->roi[0]).width;
+ thread_data[j].roi.y = (i->roi[0]).y + bit * j;
+ thread_data[j].roi.height = bit;
}
- else
+ thread_data[threads-1].roi.height = i->roi[0].height - (bit * (threads-1));
+
+ for (gint j = 0; j < threads; j++)
{
- gegl_buffer_cl_iterator_stop (i);
- g_warning ("OpenCL support enabled, but no way to execute");
- return FALSE;
+ thread_data[j].klass = point_composer_class;
+ thread_data[j].operation = operation;
+ thread_data[j].input = input?((guchar*)i->data[read]) + (bit * j * i->roi[0].width *
in_buf_bpp):NULL;
+ thread_data[j].aux = aux?((guchar*)i->data[foo]) + (bit * j * i->roi[0].width *
aux_buf_bpp):NULL;
+ thread_data[j].output = ((guchar*)i->data[0]) + (bit * j * i->roi[0].width * out_buf_bpp);
+ thread_data[j].pending = &pending;
+ thread_data[j].level = level;
+ thread_data[j].success = TRUE;
}
- }
- }
-
- return TRUE;
+ pending = threads;
-error:
- gegl_buffer_cl_iterator_stop (i);
- GEGL_NOTE (GEGL_DEBUG_OPENCL, "Error: %s", gegl_cl_errstring(cl_err));
- return FALSE;
-}
+ for (gint j = 1; j < threads; j++)
+ g_thread_pool_push (pool, &thread_data[j], NULL);
+ thread_process (&thread_data[0], NULL);
-static gboolean
-gegl_operation_point_composer_process (GeglOperation *operation,
- GeglBuffer *input,
- GeglBuffer *aux,
- GeglBuffer *output,
- const GeglRectangle *result,
- gint level)
-{
- GeglOperationClass *operation_class = GEGL_OPERATION_GET_CLASS (operation);
- GeglOperationPointComposerClass *point_composer_class = GEGL_OPERATION_POINT_COMPOSER_GET_CLASS
(operation);
- const Babl *in_format = gegl_operation_get_format (operation, "input");
- const Babl *aux_format = gegl_operation_get_format (operation, "aux");
- 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_composer_class->cl_process))
- {
- if (gegl_operation_point_composer_cl_process (operation, input, aux, output, result, level))
- return TRUE;
- }
+ while (g_atomic_int_get (&pending)) {};
+ }
+ return TRUE;
+ }
+ else
{
GeglBufferIterator *i = gegl_buffer_iterator_new (output, result, level, out_format,
GEGL_BUFFER_WRITE, GEGL_ABYSS_NONE);
- gint read = /*output == input ? 0 :*/ gegl_buffer_iterator_add (i, input, result, level, in_format,
GEGL_BUFFER_READ, GEGL_ABYSS_NONE);
- /* using separate read and write iterators for in-place ideally a single
- * readwrite indice would be sufficient
- */
+ gint foo = 0, read = 0;
+ if (input)
+ read = gegl_buffer_iterator_add (i, input, result, level, in_format, GEGL_BUFFER_READ,
GEGL_ABYSS_NONE);
if (aux)
- {
- gint foo = gegl_buffer_iterator_add (i, aux, result, level, aux_format, GEGL_BUFFER_READ,
GEGL_ABYSS_NONE);
+ foo = gegl_buffer_iterator_add (i, aux, result, level, aux_format, GEGL_BUFFER_READ,
GEGL_ABYSS_NONE);
- while (gegl_buffer_iterator_next (i))
- {
- point_composer_class->process (operation, i->data[read], i->data[foo], i->data[0],
i->length, &(i->roi[0]), level);
- }
- }
- else
+ while (gegl_buffer_iterator_next (i))
{
- while (gegl_buffer_iterator_next (i))
- {
- point_composer_class->process (operation, i->data[read], NULL, i->data[0], i->length,
&(i->roi[0]), level);
- }
+ point_composer_class->process (operation, input?i->data[read]:NULL,
+ aux?i->data[foo]:NULL,
+ i->data[0], i->length, &(i->roi[0]), level);
}
+ return TRUE;
}
- return TRUE;
}
return TRUE;
}
diff --git a/gegl/operation/gegl-operation-point-composer3.c b/gegl/operation/gegl-operation-point-composer3.c
index 7161652..8d96c9b 100644
--- a/gegl/operation/gegl-operation-point-composer3.c
+++ b/gegl/operation/gegl-operation-point-composer3.c
@@ -24,8 +24,154 @@
#include "gegl.h"
#include "gegl-operation-point-composer3.h"
#include "gegl-operation-context.h"
+#include "gegl-config.h"
+#include <sys/types.h>
+#include <unistd.h>
#include <string.h>
+typedef struct ThreadData
+{
+ GeglOperationPointComposer3Class *klass;
+ GeglOperation *operation;
+ guchar *input;
+ guchar *aux;
+ guchar *aux2;
+ guchar *output;
+ gint *pending;
+ gint *started;
+ gint level;
+ gboolean success;
+ GeglRectangle roi;
+
+ guchar *in_tmp;
+ guchar *aux_tmp;
+ guchar *aux2_tmp;
+ guchar *output_tmp;
+ const Babl *input_fish;
+ const Babl *aux_fish;
+ const Babl *aux2_fish;
+ const Babl *output_fish;
+} ThreadData;
+
+static void thread_process (gpointer thread_data, gpointer unused)
+{
+ ThreadData *data = thread_data;
+
+ guchar *input = data->input;
+ guchar *aux = data->aux;
+ guchar *aux2 = data->aux2;
+ guchar *output = data->output;
+ glong samples = data->roi.width * data->roi.height;
+
+ if (data->input_fish && input)
+ {
+ babl_process (data->input_fish, data->input, data->in_tmp, samples);
+ input = data->in_tmp;
+ }
+ if (data->aux_fish && aux)
+ {
+ babl_process (data->aux_fish, data->aux, data->aux_tmp, samples);
+ aux = data->aux_tmp;
+ }
+ if (data->aux2_fish && aux2)
+ {
+ babl_process (data->aux2_fish, data->aux2, data->aux2_tmp, samples);
+ aux2 = data->aux2_tmp;
+ }
+ if (data->output_fish)
+ output = data->output_tmp;
+
+ if (!data->klass->process (data->operation,
+ input, aux, aux2,
+ output, samples,
+ &data->roi, data->level))
+ data->success = FALSE;
+
+ if (data->output_fish)
+ babl_process (data->output_fish, data->output_tmp, data->output, samples);
+
+ 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;
+}
+
+static gboolean
+gegl_operation_composer3_process (GeglOperation *operation,
+ GeglOperationContext *context,
+ const gchar *output_prop,
+ const GeglRectangle *result,
+ gint level)
+{
+ GeglOperationComposer3Class *klass = GEGL_OPERATION_COMPOSER3_GET_CLASS (operation);
+ GeglOperationClass *op_class = GEGL_OPERATION_CLASS (klass);
+ GeglBuffer *input;
+ GeglBuffer *aux;
+ GeglBuffer *aux2;
+ GeglBuffer *output;
+ gboolean success = FALSE;
+
+ if (strcmp (output_prop, "output"))
+ {
+ g_warning ("requested processing of %s pad on a composer", output_prop);
+ return FALSE;
+ }
+
+ if (result->width == 0 || result->height == 0)
+ {
+ output = gegl_operation_context_get_target (context, "output");
+ return TRUE;
+ }
+
+ input = gegl_operation_context_get_source (context, "input");
+
+ if (op_class->want_in_place &&
+ gegl_can_do_inplace_processing (operation, input, result))
+ {
+ output = g_object_ref (input);
+ gegl_operation_context_take_object (context, "output", G_OBJECT (output));
+ }
+ else
+ {
+ output = gegl_operation_context_get_target (context, "output");
+ }
+
+ aux = gegl_operation_context_get_source (context, "aux");
+ aux2 = gegl_operation_context_get_source (context, "aux2");
+
+ /* A composer with a NULL aux, can still be valid, the
+ * subclass has to handle it.
+ */
+ if (input != NULL ||
+ aux != NULL ||
+ aux2 != NULL)
+ {
+ success = klass->process (operation, input, aux, aux2, output, result, level);
+
+ if (input)
+ g_object_unref (input);
+ if (aux)
+ g_object_unref (aux);
+ if (aux2)
+ g_object_unref (aux2);
+ }
+ else
+ {
+ g_warning ("%s received NULL input, aux, and aux2",
+ gegl_node_get_operation (operation->node));
+ }
+
+ return success;
+}
+
static gboolean gegl_operation_point_composer3_process
(GeglOperation *operation,
GeglBuffer *input,
@@ -49,13 +195,13 @@ static void prepare (GeglOperation *operation)
static void
gegl_operation_point_composer3_class_init (GeglOperationPointComposer3Class *klass)
{
- /*GObjectClass *object_class = G_OBJECT_CLASS (klass);*/
- GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
- GeglOperationComposer3Class *composer_class = GEGL_OPERATION_COMPOSER3_CLASS (klass);
+ GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
+ GeglOperationComposer3Class *composer_class = GEGL_OPERATION_COMPOSER3_CLASS (klass);
composer_class->process = gegl_operation_point_composer3_process;
+ operation_class->process = gegl_operation_composer3_process;
operation_class->prepare = prepare;
- operation_class->no_cache = TRUE;
+ operation_class->no_cache =TRUE;
operation_class->want_in_place = TRUE;
operation_class->threaded = TRUE;
}
@@ -81,50 +227,176 @@ gegl_operation_point_composer3_process (GeglOperation *operation,
const Babl *aux2_format = gegl_operation_get_format (operation, "aux2");
const Babl *out_format = gegl_operation_get_format (operation, "output");
+
if ((result->width > 0) && (result->height > 0))
{
- GeglBufferIterator *i = gegl_buffer_iterator_new (output, result, level, out_format,
GEGL_BUFFER_WRITE, GEGL_ABYSS_NONE);
- gint read = gegl_buffer_iterator_add (i, input, result, level, in_format, GEGL_BUFFER_READ,
GEGL_ABYSS_NONE);
+ const Babl *in_buf_format = input?gegl_buffer_get_format(input):NULL;
+ const Babl *aux_buf_format = aux?gegl_buffer_get_format(aux):NULL;
+ const Babl *aux2_buf_format = aux2?gegl_buffer_get_format(aux2):NULL;
+ const Babl *output_buf_format = output?gegl_buffer_get_format(output):NULL;
- if (aux)
+ if (gegl_operation_use_threading (operation, result) && result->height > 1)
+ {
+ gint threads = gegl_config ()->threads;
+ GThreadPool *pool = thread_pool ();
+ ThreadData thread_data[GEGL_MAX_THREADS];
+ GeglBufferIterator *i = gegl_buffer_iterator_new (output, result, level, output_buf_format,
GEGL_BUFFER_WRITE, GEGL_ABYSS_NONE);
+ gint foo = 0, bar = 0, read = 0;
+
+ gint in_bpp = input?babl_format_get_bytes_per_pixel (in_format):0;
+ gint aux_bpp = aux?babl_format_get_bytes_per_pixel (aux_format):0;
+ gint aux2_bpp = aux2?babl_format_get_bytes_per_pixel (aux2_format):0;
+ gint out_bpp = babl_format_get_bytes_per_pixel (out_format);
+
+ gint in_buf_bpp = input?babl_format_get_bytes_per_pixel (in_buf_format):0;
+ gint aux_buf_bpp = aux?babl_format_get_bytes_per_pixel (aux_buf_format):0;
+ gint aux2_buf_bpp = aux2?babl_format_get_bytes_per_pixel (aux2_buf_format):0;
+ gint out_buf_bpp = babl_format_get_bytes_per_pixel (output_buf_format);
+
+ gint temp_id = 0;
+
+ if (input)
{
- gint foo = gegl_buffer_iterator_add (i, aux, result, level, aux_format, GEGL_BUFFER_READ,
GEGL_ABYSS_NONE);
- if (aux2)
+ read = gegl_buffer_iterator_add (i, input, result, level, in_buf_format, GEGL_BUFFER_READ,
GEGL_ABYSS_NONE);
+ for (gint j = 0; j < threads; j ++)
+ {
+ if (in_buf_format != in_format)
{
- gint bar = gegl_buffer_iterator_add (i, aux2, result, level, aux2_format, GEGL_BUFFER_READ,
GEGL_ABYSS_NONE);
-
- while (gegl_buffer_iterator_next (i))
- {
- point_composer3_class->process (operation, i->data[read], i->data[foo], i->data[bar],
i->data[0], i->length, &(i->roi[0]), level);
- }
+ thread_data[j].input_fish = babl_fish (in_buf_format, in_format);
+ thread_data[j].in_tmp = gegl_temp_buffer (temp_id++, in_bpp * result->width * result->height);
}
- else
+ else
{
- while (gegl_buffer_iterator_next (i))
- {
- point_composer3_class->process (operation, i->data[read], i->data[foo], NULL, i->data[0],
i->length, &(i->roi[0]), level);
- }
+ thread_data[j].input_fish = NULL;
}
+ }
}
- else
+ else
+ for (gint j = 0; j < threads; j ++)
+ thread_data[j].input_fish = NULL;
+ if (aux)
{
- if (aux2)
+ foo = gegl_buffer_iterator_add (i, aux, result, level, aux_buf_format, GEGL_BUFFER_READ,
GEGL_ABYSS_NONE);
+ for (gint j = 0; j < threads; j ++)
+ {
+ if (aux_buf_format != aux_format)
{
- gint bar = gegl_buffer_iterator_add (i, aux2, result, level, aux2_format, GEGL_BUFFER_READ,
GEGL_ABYSS_NONE);
- while (gegl_buffer_iterator_next (i))
- {
- point_composer3_class->process (operation, i->data[read], NULL, i->data[bar], i->data[0],
i->length, &(i->roi[0]), level);
- }
+ thread_data[j].aux_fish = babl_fish (aux_buf_format, aux_format);
+ thread_data[j].aux_tmp = gegl_temp_buffer (temp_id++, aux_bpp * result->width *
result->height);
}
- else
+ else
+ {
+ thread_data[j].aux_fish = NULL;
+ }
+ }
+ }
+ else
+ {
+ for (gint j = 0; j < threads; j ++)
+ thread_data[j].aux_fish = NULL;
+ }
+ if (aux2)
+ {
+ bar = gegl_buffer_iterator_add (i, aux2, result, level, aux2_buf_format, GEGL_BUFFER_READ,
GEGL_ABYSS_NONE);
+ for (gint j = 0; j < threads; j ++)
+ {
+ if (aux2_buf_format != aux2_format)
{
- while (gegl_buffer_iterator_next (i))
- {
- point_composer3_class->process (operation, i->data[read], NULL, NULL, i->data[0],
i->length, &(i->roi[0]), level);
- }
+ thread_data[j].aux2_fish = babl_fish (aux2_buf_format, aux2_format);
+ thread_data[j].aux2_tmp = gegl_temp_buffer (temp_id++, aux2_bpp * result->width *
result->height);
}
+ else
+ {
+ thread_data[j].aux2_fish = NULL;
+ }
+ }
+ }
+ else
+ {
+ for (gint j = 0; j < threads; j ++)
+ thread_data[j].aux2_fish = NULL;
+ }
+
+ for (gint j = 0; j < threads; j ++)
+ {
+ if (output_buf_format != gegl_buffer_get_format (output))
+ {
+ thread_data[j].output_fish = babl_fish (out_format, output_buf_format);
+ thread_data[j].output_tmp = gegl_temp_buffer (temp_id++, out_bpp * result->width *
result->height);
+ }
+ else
+ {
+ thread_data[j].output_fish = NULL;
+ }
}
- return TRUE;
+
+ while (gegl_buffer_iterator_next (i))
+ {
+ gint threads = gegl_config()->threads;
+ gint pending;
+ gint bit;
+
+ if (i->roi[0].height < threads)
+ {
+ threads = i->roi[0].height;
+ }
+
+ bit = i->roi[0].height / threads;
+ pending = threads;
+
+ for (gint j = 0; j < threads; j++)
+ {
+ thread_data[j].roi.x = (i->roi[0]).x;
+ thread_data[j].roi.width = (i->roi[0]).width;
+ thread_data[j].roi.y = (i->roi[0]).y + bit * j;
+ thread_data[j].roi.height = bit;
+ }
+ thread_data[threads-1].roi.height = i->roi[0].height - (bit * (threads-1));
+
+ for (gint j = 0; j < threads; j++)
+ {
+ thread_data[j].klass = point_composer3_class;
+ thread_data[j].operation = operation;
+ thread_data[j].input = input?((guchar*)i->data[read]) + (bit * j * i->roi[0].width *
in_buf_bpp):NULL;
+ thread_data[j].aux = aux?((guchar*)i->data[foo]) + (bit * j * i->roi[0].width *
aux_buf_bpp):NULL;
+ thread_data[j].aux2 = aux2?((guchar*)i->data[bar]) + (bit * j * i->roi[0].width *
aux2_buf_bpp):NULL;
+ thread_data[j].output = ((guchar*)i->data[0]) + (bit * j * i->roi[0].width * out_buf_bpp);
+ thread_data[j].pending = &pending;
+ thread_data[j].level = level;
+ thread_data[j].success = TRUE;
+ }
+ pending = threads;
+
+ 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;
+ }
+ else
+ {
+ GeglBufferIterator *i = gegl_buffer_iterator_new (output, result, level, out_format,
GEGL_BUFFER_WRITE, GEGL_ABYSS_NONE);
+ gint foo = 0, bar = 0, read = 0;
+
+ if (input)
+ read = gegl_buffer_iterator_add (i, input, result, level, in_format, GEGL_BUFFER_READ,
GEGL_ABYSS_NONE);
+ if (aux)
+ foo = gegl_buffer_iterator_add (i, aux, result, level, aux_format, GEGL_BUFFER_READ,
GEGL_ABYSS_NONE);
+ if (aux2)
+ bar = gegl_buffer_iterator_add (i, aux2, result, level, aux2_format, GEGL_BUFFER_READ,
GEGL_ABYSS_NONE);
+
+ while (gegl_buffer_iterator_next (i))
+ {
+ point_composer3_class->process (operation, input?i->data[read]:NULL,
+ aux?i->data[foo]:NULL,
+ aux2?i->data[bar]:NULL,
+ i->data[0], i->length, &(i->roi[0]), level);
+ }
+ return TRUE;
+ }
}
return TRUE;
}
diff --git a/gegl/operation/gegl-operation-point-filter.c b/gegl/operation/gegl-operation-point-filter.c
index 0fbbf1c..fee7c91 100644
--- a/gegl/operation/gegl-operation-point-filter.c
+++ b/gegl/operation/gegl-operation-point-filter.c
@@ -20,15 +20,125 @@
#include "config.h"
#include <glib-object.h>
-#include <string.h>
#include "gegl.h"
-#include "gegl/gegl-debug.h"
#include "gegl-operation-point-filter.h"
#include "gegl-operation-context.h"
+#include "gegl-config.h"
+#include <sys/types.h>
+#include <unistd.h>
+#include <string.h>
+
+typedef struct ThreadData
+{
+ GeglOperationPointFilterClass *klass;
+ GeglOperation *operation;
+ guchar *input;
+ guchar *output;
+ gint *pending;
+ gint *started;
+ gint level;
+ gboolean success;
+ GeglRectangle roi;
+
+ guchar *in_tmp;
+ guchar *output_tmp;
+ const Babl *input_fish;
+ const Babl *output_fish;
+} ThreadData;
+
+static void thread_process (gpointer thread_data, gpointer unused)
+{
+ ThreadData *data = thread_data;
+
+ guchar *input = data->input;
+ guchar *output = data->output;
+ glong samples = data->roi.width * data->roi.height;
+
+ if (data->input_fish && input)
+ {
+ babl_process (data->input_fish, data->input, data->in_tmp, samples);
+ input = data->in_tmp;
+ }
+ if (data->output_fish)
+ output = data->output_tmp;
+
+ if (!data->klass->process (data->operation,
+ input,
+ output, samples,
+ &data->roi, data->level))
+ data->success = FALSE;
+
+ if (data->output_fish)
+ babl_process (data->output_fish, data->output_tmp, data->output, samples);
+
+ 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;
+}
+
+static gboolean
+gegl_operation_filter_process (GeglOperation *operation,
+ GeglOperationContext *context,
+ const gchar *output_prop,
+ const GeglRectangle *result,
+ gint level)
+{
+ GeglOperationFilterClass *klass = GEGL_OPERATION_FILTER_GET_CLASS (operation);
+ GeglOperationClass *op_class = GEGL_OPERATION_CLASS (klass);
+ GeglBuffer *input;
+ GeglBuffer *output;
+ gboolean success = FALSE;
+
+ if (strcmp (output_prop, "output"))
+ {
+ g_warning ("requested processing of %s pad on a filter", output_prop);
+ return FALSE;
+ }
+
+ if (result->width == 0 || result->height == 0)
+ {
+ output = gegl_operation_context_get_target (context, "output");
+ return TRUE;
+ }
+
+ input = gegl_operation_context_get_source (context, "input");
+
+ if (op_class->want_in_place &&
+ gegl_can_do_inplace_processing (operation, input, result))
+ {
+ output = g_object_ref (input);
+ gegl_operation_context_take_object (context, "output", G_OBJECT (output));
+ }
+ else
+ {
+ output = gegl_operation_context_get_target (context, "output");
+ }
+
+ if (input != NULL)
+ {
+ success = klass->process (operation, input, output, result, level);
-#include "opencl/gegl-cl.h"
-#include "gegl-buffer-cl-iterator.h"
+ if (input)
+ g_object_unref (input);
+ }
+ else
+ {
+ g_warning ("%s received NULL input",
+ gegl_node_get_operation (operation->node));
+ }
+
+ return success;
+}
static gboolean gegl_operation_point_filter_process
(GeglOperation *operation,
@@ -41,145 +151,153 @@ G_DEFINE_TYPE (GeglOperationPointFilter, gegl_operation_point_filter, GEGL_TYPE_
static void prepare (GeglOperation *operation)
{
- gegl_operation_set_format (operation, "input", babl_format ("RGBA float"));
- gegl_operation_set_format (operation, "output", babl_format ("RGBA float"));
+ const Babl *format = babl_format ("RGBA float");
+ gegl_operation_set_format (operation, "input", format);
+ gegl_operation_set_format (operation, "output", format);
}
static void
gegl_operation_point_filter_class_init (GeglOperationPointFilterClass *klass)
{
- GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
+ GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
+ GeglOperationFilterClass *filter_class = GEGL_OPERATION_FILTER_CLASS (klass);
- GEGL_OPERATION_FILTER_CLASS(klass)->process = gegl_operation_point_filter_process;
+ 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->no_cache =TRUE;
operation_class->want_in_place = TRUE;
-
- klass->process = NULL;
- klass->cl_process = NULL;
+ operation_class->threaded = TRUE;
}
static void
gegl_operation_point_filter_init (GeglOperationPointFilter *self)
{
+
}
static gboolean
-gegl_operation_point_filter_cl_process (GeglOperation *operation,
- GeglBuffer *input,
- GeglBuffer *output,
- const GeglRectangle *result,
- gint level)
+gegl_operation_point_filter_process (GeglOperation *operation,
+ GeglBuffer *input,
+ GeglBuffer *output,
+ const GeglRectangle *result,
+ gint level)
{
- const Babl *in_format = gegl_operation_get_format (operation, "input");
- const Babl *out_format = gegl_operation_get_format (operation, "output");
-
- GeglOperationClass *operation_class = GEGL_OPERATION_GET_CLASS (operation);
GeglOperationPointFilterClass *point_filter_class = GEGL_OPERATION_POINT_FILTER_GET_CLASS (operation);
+ const Babl *in_format = gegl_operation_get_format (operation, "input");
+ const Babl *out_format = gegl_operation_get_format (operation, "output");
- GeglBufferClIterator *iter = NULL;
-
- cl_int cl_err = 0;
- gboolean err;
- /* non-texturizable format! */
- if (!gegl_cl_color_babl (in_format, NULL) ||
- !gegl_cl_color_babl (out_format, NULL))
+ if ((result->width > 0) && (result->height > 0))
{
- GEGL_NOTE (GEGL_DEBUG_OPENCL, "Non-texturizable format!");
- return FALSE;
- }
-
- GEGL_NOTE (GEGL_DEBUG_OPENCL, "GEGL_OPERATION_POINT_FILTER: %s", operation_class->name);
-
- /* Process */
- iter = gegl_buffer_cl_iterator_new (output, result, out_format, GEGL_CL_BUFFER_WRITE);
+ const Babl *in_buf_format = input?gegl_buffer_get_format(input):NULL;
+ const Babl *output_buf_format = output?gegl_buffer_get_format(output):NULL;
- gegl_buffer_cl_iterator_add (iter, input, result, in_format, GEGL_CL_BUFFER_READ, GEGL_ABYSS_NONE);
+ if (gegl_operation_use_threading (operation, result) && result->height > 1)
+ {
+ gint threads = gegl_config ()->threads;
+ GThreadPool *pool = thread_pool ();
+ ThreadData thread_data[GEGL_MAX_THREADS];
+ GeglBufferIterator *i = gegl_buffer_iterator_new (output, result, level, output_buf_format,
GEGL_BUFFER_WRITE, GEGL_ABYSS_NONE);
+ gint read = 0;
- while (gegl_buffer_cl_iterator_next (iter, &err))
- {
- if (err)
- return FALSE;
+ gint in_bpp = input?babl_format_get_bytes_per_pixel (in_format):0;
+ gint out_bpp = babl_format_get_bytes_per_pixel (out_format);
+ gint in_buf_bpp = input?babl_format_get_bytes_per_pixel (in_buf_format):0;
+ gint out_buf_bpp = babl_format_get_bytes_per_pixel (output_buf_format);
+ gint temp_id = 0;
- if (point_filter_class->cl_process)
+ if (input)
{
- err = point_filter_class->cl_process (operation, iter->tex[1], iter->tex[0],
- iter->size[0], &iter->roi[0], level);
- if (err)
+ read = gegl_buffer_iterator_add (i, input, result, level, in_buf_format, GEGL_BUFFER_READ,
GEGL_ABYSS_NONE);
+ for (gint j = 0; j < threads; j ++)
+ {
+ if (in_buf_format != in_format)
{
- GEGL_NOTE (GEGL_DEBUG_OPENCL, "Error: %s", operation_class->name);
- gegl_buffer_cl_iterator_stop (iter);
- return FALSE;
+ thread_data[j].input_fish = babl_fish (in_buf_format, in_format);
+ thread_data[j].in_tmp = gegl_temp_buffer (temp_id++, in_bpp * result->width * result->height);
}
+ else
+ {
+ thread_data[j].input_fish = NULL;
+ }
+ }
}
- else if (operation_class->cl_data)
- {
- gint p = 0;
- GeglClRunData *cl_data = operation_class->cl_data;
-
- cl_err = gegl_clSetKernelArg (cl_data->kernel[0], p++, sizeof(cl_mem), (void*)&iter->tex[1]);
- CL_CHECK;
- cl_err = gegl_clSetKernelArg (cl_data->kernel[0], p++, sizeof(cl_mem), (void*)&iter->tex[0]);
- CL_CHECK;
-
- gegl_operation_cl_set_kernel_args (operation, cl_data->kernel[0], &p, &cl_err);
- CL_CHECK;
-
- cl_err = gegl_clEnqueueNDRangeKernel (gegl_cl_get_command_queue (),
- cl_data->kernel[0], 1,
- NULL, &iter->size[0], NULL,
- 0, NULL, NULL);
- CL_CHECK;
- }
- else
+ else
+ for (gint j = 0; j < threads; j ++)
+ thread_data[j].input_fish = NULL;
+
+ for (gint j = 0; j < threads; j ++)
{
- g_warning ("OpenCL support enabled, but no way to execute");
- gegl_buffer_cl_iterator_stop (iter);
- return FALSE;
+ if (output_buf_format != gegl_buffer_get_format (output))
+ {
+ thread_data[j].output_fish = babl_fish (out_format, output_buf_format);
+ thread_data[j].output_tmp = gegl_temp_buffer (temp_id++, out_bpp * result->width *
result->height);
+ }
+ else
+ {
+ thread_data[j].output_fish = NULL;
+ }
}
- }
- return TRUE;
+ while (gegl_buffer_iterator_next (i))
+ {
+ gint threads = gegl_config()->threads;
+ gint pending;
+ gint bit;
-error:
- GEGL_NOTE (GEGL_DEBUG_OPENCL, "Error: %s", gegl_cl_errstring (cl_err));
- if (iter)
- gegl_buffer_cl_iterator_stop (iter);
- return FALSE;
-}
+ if (i->roi[0].height < threads)
+ {
+ threads = i->roi[0].height;
+ }
-static gboolean
-gegl_operation_point_filter_process (GeglOperation *operation,
- GeglBuffer *input,
- GeglBuffer *output,
- const GeglRectangle *result,
- gint level)
-{
- const Babl *in_format = gegl_operation_get_format (operation, "input");
- const Babl *out_format = gegl_operation_get_format (operation, "output");
- GeglOperationPointFilterClass *point_filter_class;
+ bit = i->roi[0].height / threads;
+ pending = threads;
- GeglOperationClass *operation_class = GEGL_OPERATION_GET_CLASS (operation);
- point_filter_class = GEGL_OPERATION_POINT_FILTER_GET_CLASS (operation);
+ for (gint j = 0; j < threads; j++)
+ {
+ thread_data[j].roi.x = (i->roi[0]).x;
+ thread_data[j].roi.width = (i->roi[0]).width;
+ thread_data[j].roi.y = (i->roi[0]).y + bit * j;
+ thread_data[j].roi.height = bit;
+ }
+ thread_data[threads-1].roi.height = i->roi[0].height - (bit * (threads-1));
+
+ for (gint j = 0; j < threads; j++)
+ {
+ thread_data[j].klass = point_filter_class;
+ thread_data[j].operation = operation;
+ thread_data[j].input = input?((guchar*)i->data[read]) + (bit * j * i->roi[0].width *
in_buf_bpp):NULL;
+ thread_data[j].output = ((guchar*)i->data[0]) + (bit * j * i->roi[0].width * out_buf_bpp);
+ thread_data[j].pending = &pending;
+ thread_data[j].level = level;
+ thread_data[j].success = TRUE;
+ }
+ pending = threads;
- if ((result->width > 0) && (result->height > 0))
- {
- if (gegl_operation_use_opencl (operation) &&
- (operation_class->cl_data || point_filter_class->cl_process))
- {
- if (gegl_operation_point_filter_cl_process (operation, input, output, result, level))
- return TRUE;
- }
+ 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;
+ }
+ else
{
GeglBufferIterator *i = gegl_buffer_iterator_new (output, result, level, out_format,
GEGL_BUFFER_WRITE, GEGL_ABYSS_NONE);
- gint read = /*output == input ? 0 :*/ gegl_buffer_iterator_add (i, input, result, level, in_format,
GEGL_BUFFER_READ, GEGL_ABYSS_NONE);
- /* using separate read and write iterators for in-place ideally a single
- * readwrite indice would be sufficient
- */
- while (gegl_buffer_iterator_next (i))
- point_filter_class->process (operation, i->data[read], i->data[0], i->length, &i->roi[0], level);
+ gint read = 0;
+
+ if (input)
+ read = gegl_buffer_iterator_add (i, input, result, level, in_format, GEGL_BUFFER_READ,
GEGL_ABYSS_NONE);
+
+ while (gegl_buffer_iterator_next (i))
+ {
+ point_filter_class->process (operation, input?i->data[read]:NULL,
+ i->data[0], i->length, &(i->roi[0]), level);
+ }
+ return TRUE;
}
}
return TRUE;
diff --git a/gegl/operation/gegl-operation-point-render.c b/gegl/operation/gegl-operation-point-render.c
index e46c2db..01c5daa 100644
--- a/gegl/operation/gegl-operation-point-render.c
+++ b/gegl/operation/gegl-operation-point-render.c
@@ -60,6 +60,7 @@ gegl_operation_point_render_class_init (GeglOperationPointRenderClass *klass)
operation_class->get_cached_region = NULL; /* we are able to compute anything
anywhere when we're our kind
of class */
+ operation_class->threaded = TRUE;
}
static void
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]