Commit 172d9b4f authored by Ell's avatar Ell Committed by Øyvind "pippin" Kolås

operation, transform: use separate input buffers for different threads

Use gegl_operation_context_dup_input_maybe_copy(), added in the
previous commit, in GimpOperationFilter, GimpOperationComposer,
GimpOperationComposer3, and OpTransform (however, *not* in the
corresponding point ops), to (potentially) create a separate copy
of the input buffer for each thread, to avoid lock contention over
the input buffer's tile-storage lock.  Use the input buffer
directly only for the first chunk, which is processed by the caller
thread.

This significantly improves performance of operations that randomly
access the input buffer (e.g., using a sampler), and seems not to
pessimize operations with a more regular access pattern (e.g.,
using an iterator, or scan rows).
parent 9cb3c7a2
......@@ -101,7 +101,7 @@ typedef struct ThreadData
{
GeglOperationComposerClass *klass;
GeglOperation *operation;
GeglBuffer *input;
GeglOperationContext *context;
GeglBuffer *aux;
GeglBuffer *output;
gint *pending;
......@@ -110,12 +110,23 @@ typedef struct ThreadData
GeglRectangle roi;
} ThreadData;
static void thread_process (gpointer thread_data, gpointer unused)
static void thread_process (gpointer thread_data, gpointer input)
{
ThreadData *data = thread_data;
if (! input)
{
input = gegl_operation_context_dup_input_maybe_copy (data->context,
"input", &data->roi);
}
if (!data->klass->process (data->operation,
data->input, data->aux, data->output, &data->roi, data->level))
input, data->aux, data->output,
&data->roi, data->level))
data->success = FALSE;
g_object_unref (input);
g_atomic_int_add (data->pending, -1);
}
......@@ -197,7 +208,7 @@ gegl_operation_composer_process (GeglOperation *operation,
{
thread_data[i].klass = klass;
thread_data[i].operation = operation;
thread_data[i].input = input;
thread_data[i].context = context;
thread_data[i].aux = aux;
thread_data[i].output = output;
thread_data[i].pending = &pending;
......@@ -207,7 +218,7 @@ gegl_operation_composer_process (GeglOperation *operation,
for (gint i = 1; i < threads; i++)
g_thread_pool_push (pool, &thread_data[i], NULL);
thread_process (&thread_data[0], NULL);
thread_process (&thread_data[0], g_object_ref (input));
while (g_atomic_int_get (&pending)) {};
......
......@@ -110,7 +110,7 @@ typedef struct ThreadData
{
GeglOperationComposer3Class *klass;
GeglOperation *operation;
GeglBuffer *input;
GeglOperationContext *context;
GeglBuffer *aux;
GeglBuffer *aux2;
GeglBuffer *output;
......@@ -120,13 +120,23 @@ typedef struct ThreadData
GeglRectangle roi;
} ThreadData;
static void thread_process (gpointer thread_data, gpointer unused)
static void thread_process (gpointer thread_data, gpointer input)
{
ThreadData *data = thread_data;
if (! input)
{
input = gegl_operation_context_dup_input_maybe_copy (data->context,
"input", &data->roi);
}
if (!data->klass->process (data->operation,
data->input, data->aux, data->aux2,
data->output, &data->roi, data->level))
input, data->aux, data->aux2,
data->output, &data->roi, data->level))
data->success = FALSE;
g_object_unref (input);
g_atomic_int_add (data->pending, -1);
}
......@@ -219,7 +229,7 @@ gegl_operation_composer3_process (GeglOperation *operation,
{
thread_data[i].klass = klass;
thread_data[i].operation = operation;
thread_data[i].input = input;
thread_data[i].context = context;
thread_data[i].aux = aux;
thread_data[i].aux2 = aux2;
thread_data[i].output = output;
......@@ -230,7 +240,7 @@ gegl_operation_composer3_process (GeglOperation *operation,
for (gint i = 1; i < threads; i++)
g_thread_pool_push (pool, &thread_data[i], NULL);
thread_process (&thread_data[0], NULL);
thread_process (&thread_data[0], g_object_ref (input));
while (g_atomic_int_get (&pending)) {};
......
......@@ -109,7 +109,7 @@ typedef struct ThreadData
{
GeglOperationFilterClass *klass;
GeglOperation *operation;
GeglBuffer *input;
GeglOperationContext *context;
GeglBuffer *output;
gint *pending;
gint level;
......@@ -117,12 +117,22 @@ typedef struct ThreadData
GeglRectangle roi;
} ThreadData;
static void thread_process (gpointer thread_data, gpointer unused)
static void thread_process (gpointer thread_data, gpointer input)
{
ThreadData *data = thread_data;
if (! input)
{
input = gegl_operation_context_dup_input_maybe_copy (data->context,
"input", &data->roi);
}
if (!data->klass->process (data->operation,
data->input, data->output, &data->roi, data->level))
input, data->output, &data->roi, data->level))
data->success = FALSE;
g_object_unref (input);
g_atomic_int_add (data->pending, -1);
}
......@@ -219,7 +229,7 @@ gegl_operation_filter_process (GeglOperation *operation,
{
thread_data[i].klass = klass;
thread_data[i].operation = operation;
thread_data[i].input = input;
thread_data[i].context = context;
thread_data[i].output = output;
thread_data[i].pending = &pending;
thread_data[i].level = level;
......@@ -228,7 +238,7 @@ gegl_operation_filter_process (GeglOperation *operation,
for (gint i = 1; i < threads; i++)
g_thread_pool_push (pool, &thread_data[i], NULL);
thread_process (&thread_data[0], NULL);
thread_process (&thread_data[0], g_object_ref (input));
while (g_atomic_int_get (&pending)) {};
......
......@@ -750,7 +750,7 @@ typedef struct ThreadData
GeglOperation *operation;
GeglBuffer *input;
GeglOperationContext *context;
GeglBuffer *output;
gint *pending;
GeglMatrix3 *matrix;
......@@ -759,16 +759,25 @@ typedef struct ThreadData
GeglRectangle roi;
} ThreadData;
static void thread_process (gpointer thread_data, gpointer unused)
static void thread_process (gpointer thread_data, gpointer input)
{
ThreadData *data = thread_data;
if (! input)
{
input = gegl_operation_context_dup_input_maybe_copy (data->context,
"input", &data->roi);
}
data->func (data->operation,
data->output,
data->input,
input,
data->matrix,
&data->roi,
data->level);
data->success = FALSE;
g_object_unref (input);
g_atomic_int_add (data->pending, -1);
}
......@@ -1256,7 +1265,7 @@ gegl_transform_process (GeglOperation *operation,
thread_data[i].func = func;
thread_data[i].matrix = &matrix;
thread_data[i].operation = operation;
thread_data[i].input = input;
thread_data[i].context = context;
thread_data[i].output = output;
thread_data[i].pending = &pending;
thread_data[i].level = level;
......@@ -1265,7 +1274,7 @@ gegl_transform_process (GeglOperation *operation,
for (gint i = 1; i < threads; i++)
g_thread_pool_push (pool, &thread_data[i], NULL);
thread_process (&thread_data[0], NULL);
thread_process (&thread_data[0], g_object_ref (input));
while (g_atomic_int_get (&pending)) {};
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment