Commit 07aacf73 authored by Dimitris Papavasiliou's avatar Dimitris Papavasiliou Committed by Daniel Sabo

operations: add a cell noise operation

Added a cell noise operation implementing the texture function described in

    Steven Worley. 1996. A cellular texture basis function.
    In Proceedings of the 23rd annual conference on Computer
    graphics and interactive techniques (SIGGRAPH '96).
parent 2cb55d43
#define MAX_RANK 3
/* Random feature counts following the Poisson distribution with
lambda equal to 7. */
static const __constant char poisson[256] = {
7, 9, 12, 12, 8, 7, 5, 5, 6, 7, 8, 6, 10, 7, 6, 2, 8, 3, 9, 5, 13, 10, 9,
8, 8, 9, 3, 8, 9, 6, 8, 7, 4, 9, 6, 3, 10, 7, 7, 7, 6, 7, 4, 14, 7, 6, 11,
7, 7, 7, 12, 7, 10, 6, 8, 11, 3, 5, 7, 7, 8, 7, 9, 8, 5, 8, 11, 3, 4, 5, 8,
8, 7, 8, 9, 2, 7, 8, 12, 4, 8, 2, 11, 8, 14, 7, 8, 2, 3, 10, 4, 6, 9, 5, 8,
7, 10, 10, 10, 14, 5, 7, 6, 4, 5, 6, 11, 8, 7, 3, 11, 5, 5, 2, 9, 7, 7, 7,
9, 2, 7, 6, 9, 7, 6, 5, 12, 5, 3, 11, 9, 12, 8, 6, 8, 6, 8, 5, 5, 7, 5, 2,
9, 5, 5, 8, 11, 8, 8, 10, 6, 4, 7, 14, 7, 3, 10, 7, 7, 4, 9, 10, 10, 9, 8,
8, 7, 6, 5, 10, 10, 5, 10, 7, 7, 10, 7, 4, 9, 9, 6, 8, 5, 10, 7, 3, 9, 9,
7, 8, 9, 7, 5, 7, 6, 5, 5, 12, 4, 7, 5, 5, 4, 5, 7, 10, 8, 7, 9, 4, 6, 11,
6, 3, 7, 8, 9, 5, 8, 6, 7, 8, 7, 7, 3, 7, 7, 9, 4, 5, 5, 6, 9, 7, 6, 12, 4,
9, 10, 8, 8, 6, 4, 9, 9, 8, 11, 6, 8, 13, 8, 9, 12, 6, 9, 8
};
static uint
philox (uint s,
uint t,
uint k)
{
ulong p;
int i;
for (i = 0 ; i < 3 ; i += 1)
{
p = s * 0xcd9e8d57ul;
s = ((uint)(p >> 32)) ^ t ^ k;
t = (uint)p;
k += 0x9e3779b9u;
}
return s;
}
static float
lcg (uint *hash)
{
return (*hash = *hash * 1664525u + 1013904223u) / 4294967296.0f;
}
static void
search_box (float *closest,
uint *feature,
int s,
int t,
float x,
float y,
float shape,
uint rank,
uint seed)
{
uint hash;
int i, n;
hash = philox ((uint)s, (uint)t, seed);
n = poisson[hash >> 24];
for (i = 0 ; i < n ; i += 1)
{
float delta_x, delta_y, d;
int j, k;
/* Calculate the distance to each feature point. */
delta_x = s + lcg (&hash) - x;
delta_y = t + lcg (&hash) - y;
if (shape == 2)
d = delta_x * delta_x + delta_y * delta_y;
else if (shape == 1)
d = fabs (delta_x) + fabs (delta_y);
else
d = pow (fabs (delta_x), shape) +
pow (fabs (delta_y), shape);
/* Insert it into the list of n closest distances if needed. */
for (j = 0 ; j < rank && d > closest[j] ; j += 1);
if (j < rank)
{
for (k = rank - 1 ; k > j ; k -= 1)
{
closest[k] = closest[k - 1];
}
closest[j] = d;
if (j == rank - 1)
*feature = hash;
}
}
}
__kernel void kernel_noise (__global float *out,
const int x_0,
const int y_0,
const uint iterations,
float scale,
float shape,
uint rank,
uint seed,
int palettize)
{
const int gidx = get_global_id(0);
const int gidy = get_global_id(1);
float c, d, n, closest[MAX_RANK], *d_0 = &closest[MAX_RANK - 1];
uint feature;
int i, j;
for (j = 0, n = 0, c = 1, d = scale;
j < iterations;
c *= 2, d *= 2, j += 1)
{
float d_l, d_r, d_t, d_b;
float x = (float)(gidx + x_0) * d;
float y = (float)(gidy + y_0) * d;
int s = (int)floor(x);
int t = (int)floor(y);
for (i = 0 ; i < rank ; closest[i] = 1.0 / 0.0, i += 1);
/* Search the box the point is in. */
search_box (closest, &feature, s, t, x, y, shape, rank, seed);
d_0 = &closest[rank - 1];
d_l = x - s; d_l *= d_l;
d_r = 1.0 - x + s; d_r *= d_r;
d_b = y - t; d_b *= d_b;
d_t = 1.0 - y + t; d_t *= d_t;
/* Search adjacent boxes if it is possible for them to contain a
* nearby feature point. */
if (d_l < *d_0)
{
if (d_l + d_b < *d_0)
search_box (closest, &feature, s - 1, t - 1, x, y,
shape, rank, seed);
search_box (closest, &feature, s - 1, t, x, y,
shape, rank, seed);
if (d_l + d_t < *d_0)
search_box (closest, &feature, s - 1, t + 1, x, y,
shape, rank, seed);
}
if (d_b < *d_0)
search_box (closest, &feature, s, t - 1, x, y,
shape, rank, seed);
if (d_t < *d_0)
search_box (closest, &feature, s, t + 1, x, y,
shape, rank, seed);
if (d_r < *d_0)
{
if (d_r + d_b < *d_0)
search_box (closest, &feature, s + 1, t - 1, x, y,
shape, rank, seed);
search_box (closest, &feature, s + 1, t, x, y,
shape, rank, seed);
if (d_r + d_t < *d_0)
search_box (closest, &feature, s + 1, t + 1, x, y,
shape, rank, seed);
}
/* If palettized output is requested return the normalized hash of
* the closest feature point, otherwise return the closest
* distance. */
if(palettize)
{
n += feature / 4294967295.0f / c;
}
else
{
n += pow(closest[rank - 1], 1 / shape) / c;
}
}
out[gidy * get_global_size(0) + gidx] = n;
}
static const char* noise_cell_cl_source =
"#define MAX_RANK 3 \n"
" \n"
"/* Random feature counts following the Poisson distribution with \n"
" lambda equal to 7. */ \n"
" \n"
"static const __constant char poisson[256] = { \n"
" 7, 9, 12, 12, 8, 7, 5, 5, 6, 7, 8, 6, 10, 7, 6, 2, 8, 3, 9, 5, 13, 10, 9, \n"
" 8, 8, 9, 3, 8, 9, 6, 8, 7, 4, 9, 6, 3, 10, 7, 7, 7, 6, 7, 4, 14, 7, 6, 11, \n"
" 7, 7, 7, 12, 7, 10, 6, 8, 11, 3, 5, 7, 7, 8, 7, 9, 8, 5, 8, 11, 3, 4, 5, 8, \n"
" 8, 7, 8, 9, 2, 7, 8, 12, 4, 8, 2, 11, 8, 14, 7, 8, 2, 3, 10, 4, 6, 9, 5, 8, \n"
" 7, 10, 10, 10, 14, 5, 7, 6, 4, 5, 6, 11, 8, 7, 3, 11, 5, 5, 2, 9, 7, 7, 7, \n"
" 9, 2, 7, 6, 9, 7, 6, 5, 12, 5, 3, 11, 9, 12, 8, 6, 8, 6, 8, 5, 5, 7, 5, 2, \n"
" 9, 5, 5, 8, 11, 8, 8, 10, 6, 4, 7, 14, 7, 3, 10, 7, 7, 4, 9, 10, 10, 9, 8, \n"
" 8, 7, 6, 5, 10, 10, 5, 10, 7, 7, 10, 7, 4, 9, 9, 6, 8, 5, 10, 7, 3, 9, 9, \n"
" 7, 8, 9, 7, 5, 7, 6, 5, 5, 12, 4, 7, 5, 5, 4, 5, 7, 10, 8, 7, 9, 4, 6, 11, \n"
" 6, 3, 7, 8, 9, 5, 8, 6, 7, 8, 7, 7, 3, 7, 7, 9, 4, 5, 5, 6, 9, 7, 6, 12, 4, \n"
" 9, 10, 8, 8, 6, 4, 9, 9, 8, 11, 6, 8, 13, 8, 9, 12, 6, 9, 8 \n"
"}; \n"
" \n"
"static uint \n"
"philox (uint s, \n"
" uint t, \n"
" uint k) \n"
"{ \n"
" ulong p; \n"
" int i; \n"
" \n"
" for (i = 0 ; i < 3 ; i += 1) \n"
" { \n"
" p = s * 0xcd9e8d57ul; \n"
" \n"
" s = ((uint)(p >> 32)) ^ t ^ k; \n"
" t = (uint)p; \n"
" \n"
" k += 0x9e3779b9u; \n"
" } \n"
" \n"
" return s; \n"
"} \n"
" \n"
"static float \n"
"lcg (uint *hash) \n"
"{ \n"
" return (*hash = *hash * 1664525u + 1013904223u) / 4294967296.0f; \n"
"} \n"
" \n"
"static void \n"
"search_box (float *closest, \n"
" uint *feature, \n"
" int s, \n"
" int t, \n"
" float x, \n"
" float y, \n"
" float shape, \n"
" uint rank, \n"
" uint seed) \n"
"{ \n"
" uint hash; \n"
" int i, n; \n"
" \n"
" hash = philox ((uint)s, (uint)t, seed); \n"
" n = poisson[hash >> 24]; \n"
" \n"
" for (i = 0 ; i < n ; i += 1) \n"
" { \n"
" float delta_x, delta_y, d; \n"
" int j, k; \n"
" \n"
" /* Calculate the distance to each feature point. */ \n"
" \n"
" delta_x = s + lcg (&hash) - x; \n"
" delta_y = t + lcg (&hash) - y; \n"
" \n"
" if (shape == 2) \n"
" d = delta_x * delta_x + delta_y * delta_y; \n"
" else if (shape == 1) \n"
" d = fabs (delta_x) + fabs (delta_y); \n"
" else \n"
" d = pow (fabs (delta_x), shape) + \n"
" pow (fabs (delta_y), shape); \n"
" \n"
" /* Insert it into the list of n closest distances if needed. */ \n"
" \n"
" for (j = 0 ; j < rank && d > closest[j] ; j += 1); \n"
" \n"
" if (j < rank) \n"
" { \n"
" for (k = rank - 1 ; k > j ; k -= 1) \n"
" { \n"
" closest[k] = closest[k - 1]; \n"
" } \n"
" \n"
" closest[j] = d; \n"
" \n"
" if (j == rank - 1) \n"
" *feature = hash; \n"
" } \n"
" } \n"
"} \n"
" \n"
"__kernel void kernel_noise (__global float *out, \n"
" const int x_0, \n"
" const int y_0, \n"
" const uint iterations, \n"
" float scale, \n"
" float shape, \n"
" uint rank, \n"
" uint seed, \n"
" int palettize) \n"
"{ \n"
" const int gidx = get_global_id(0); \n"
" const int gidy = get_global_id(1); \n"
" \n"
" float c, d, n, closest[MAX_RANK], *d_0 = &closest[MAX_RANK - 1]; \n"
" uint feature; \n"
" int i, j; \n"
" \n"
" for (j = 0, n = 0, c = 1, d = scale; \n"
" j < iterations; \n"
" c *= 2, d *= 2, j += 1) \n"
" { \n"
" float d_l, d_r, d_t, d_b; \n"
" float x = (float)(gidx + x_0) * d; \n"
" float y = (float)(gidy + y_0) * d; \n"
" int s = (int)floor(x); \n"
" int t = (int)floor(y); \n"
" \n"
" for (i = 0 ; i < rank ; closest[i] = 1.0 / 0.0, i += 1); \n"
" \n"
" /* Search the box the point is in. */ \n"
" \n"
" search_box (closest, &feature, s, t, x, y, shape, rank, seed); \n"
" \n"
" d_0 = &closest[rank - 1]; \n"
" d_l = x - s; d_l *= d_l; \n"
" d_r = 1.0 - x + s; d_r *= d_r; \n"
" d_b = y - t; d_b *= d_b; \n"
" d_t = 1.0 - y + t; d_t *= d_t; \n"
" \n"
" /* Search adjacent boxes if it is possible for them to contain a \n"
" * nearby feature point. */ \n"
" \n"
" if (d_l < *d_0) \n"
" { \n"
" if (d_l + d_b < *d_0) \n"
" search_box (closest, &feature, s - 1, t - 1, x, y, \n"
" shape, rank, seed); \n"
" \n"
" search_box (closest, &feature, s - 1, t, x, y, \n"
" shape, rank, seed); \n"
" \n"
" if (d_l + d_t < *d_0) \n"
" search_box (closest, &feature, s - 1, t + 1, x, y, \n"
" shape, rank, seed); \n"
" } \n"
" \n"
" if (d_b < *d_0) \n"
" search_box (closest, &feature, s, t - 1, x, y, \n"
" shape, rank, seed); \n"
" \n"
" if (d_t < *d_0) \n"
" search_box (closest, &feature, s, t + 1, x, y, \n"
" shape, rank, seed); \n"
" \n"
" if (d_r < *d_0) \n"
" { \n"
" if (d_r + d_b < *d_0) \n"
" search_box (closest, &feature, s + 1, t - 1, x, y, \n"
" shape, rank, seed); \n"
" \n"
" search_box (closest, &feature, s + 1, t, x, y, \n"
" shape, rank, seed); \n"
" \n"
" if (d_r + d_t < *d_0) \n"
" search_box (closest, &feature, s + 1, t + 1, x, y, \n"
" shape, rank, seed); \n"
" } \n"
" \n"
" /* If palettized output is requested return the normalized hash of \n"
" * the closest feature point, otherwise return the closest \n"
" * distance. */ \n"
" \n"
" if(palettize) \n"
" { \n"
" n += feature / 4294967295.0f / c; \n"
" } \n"
" else \n"
" { \n"
" n += pow(closest[rank - 1], 1 / shape) / c; \n"
" } \n"
" } \n"
" \n"
" out[gidy * get_global_size(0) + gidx] = n; \n"
"} \n"
;
......@@ -77,6 +77,7 @@ op_LTLIBRARIES = \
noise-rgb.la \
noise-slur.la \
noise-spread.la \
noise-cell.la \
noise.la \
oilify.la \
opacity.la \
......@@ -117,4 +118,4 @@ op_LTLIBRARIES = \
weighted-blend.la \
whirl-pinch.la \
wind.la \
write-buffer.la
\ No newline at end of file
write-buffer.la
/* This file is an image processing operation for 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 2014 Dimitris Papavasiliou <dpapavas@google.com>
*/
/* This plug-in generates cellular noise textures based on the
* function described in the paper
*
* Steven Worley. 1996. A cellular texture basis function.
* In Proceedings of the 23rd annual conference on Computer
* graphics and interactive techniques (SIGGRAPH '96).
*
* Comments and improvements for this code are welcome.
*/
#include "config.h"
#include <glib/gi18n-lib.h>
#define MAX_RANK 3
#ifdef GEGL_CHANT_PROPERTIES
gegl_chant_seed (seed, rand, _("Random seed"),
_("The random seed for the noise function"))
gegl_chant_double (scale, _("Scale"), 0, 20.0, 1.0,
_("The scale of the noise function"))
gegl_chant_double (shape, _("Shape"), 1.0, 2.0, 2.0,
_("Interpolate between Manhattan and Euclidean distance."))
gegl_chant_int (rank, _("Rank"), 1, MAX_RANK, 1,
_("Select the n-th closest point"))
gegl_chant_int (iterations, _("Iterations"), 1, 20, 1,
_("The number of noise octaves."))
gegl_chant_boolean (palettize, _("Palettize"), FALSE,
_("Fill each cell with a random color"))
#else
#define GEGL_CHANT_TYPE_POINT_RENDER
#define GEGL_CHANT_C_FILE "noise-cell.c"
#include "gegl-chant.h"
#include <gegl-buffer-cl-iterator.h>
#include <gegl-debug.h>
#include <math.h>
#include "opencl/noise-cell.cl.h"
/* Random feature counts following the Poisson distribution with
lambda equal to 7. */
static const gint poisson[256] = {
7, 9, 12, 12, 8, 7, 5, 5, 6, 7, 8, 6, 10, 7, 6, 2, 8, 3, 9, 5, 13, 10, 9,
8, 8, 9, 3, 8, 9, 6, 8, 7, 4, 9, 6, 3, 10, 7, 7, 7, 6, 7, 4, 14, 7, 6, 11,
7, 7, 7, 12, 7, 10, 6, 8, 11, 3, 5, 7, 7, 8, 7, 9, 8, 5, 8, 11, 3, 4, 5, 8,
8, 7, 8, 9, 2, 7, 8, 12, 4, 8, 2, 11, 8, 14, 7, 8, 2, 3, 10, 4, 6, 9, 5, 8,
7, 10, 10, 10, 14, 5, 7, 6, 4, 5, 6, 11, 8, 7, 3, 11, 5, 5, 2, 9, 7, 7, 7,
9, 2, 7, 6, 9, 7, 6, 5, 12, 5, 3, 11, 9, 12, 8, 6, 8, 6, 8, 5, 5, 7, 5, 2,
9, 5, 5, 8, 11, 8, 8, 10, 6, 4, 7, 14, 7, 3, 10, 7, 7, 4, 9, 10, 10, 9, 8,
8, 7, 6, 5, 10, 10, 5, 10, 7, 7, 10, 7, 4, 9, 9, 6, 8, 5, 10, 7, 3, 9, 9,
7, 8, 9, 7, 5, 7, 6, 5, 5, 12, 4, 7, 5, 5, 4, 5, 7, 10, 8, 7, 9, 4, 6, 11,
6, 3, 7, 8, 9, 5, 8, 6, 7, 8, 7, 7, 3, 7, 7, 9, 4, 5, 5, 6, 9, 7, 6, 12, 4,
9, 10, 8, 8, 6, 4, 9, 9, 8, 11, 6, 8, 13, 8, 9, 12, 6, 9, 8
};
typedef struct
{
gdouble shape;
gdouble closest[MAX_RANK];
guint feature, rank, seed;
gboolean palettize;
} Context;
static GeglClRunData *cl_data = NULL;
static inline guint
philox (guint s,
guint t,
guint k)
{
guint64 p;
gint i;
/* For details regarding this hash function consult:
Salmon, J.K.; Moraes, M.A.; Dror, R.O.; Shaw, D.E., "Parallel
random numbers: As easy as 1, 2, 3," High Performance Computing,
Networking, Storage and Analysis (SC), 2011 International
Conference for , vol., no., pp.1,12, 12-18 Nov. 2011 */\
for (i = 0 ; i < 3 ; i += 1)
{
p = s * (guint64)0xcd9e8d57;
s = ((guint)(p >> 32)) ^ t ^ k;
t = (guint)p;
k += 0x9e3779b9;
}
return s;
}
static inline gdouble
lcg (guint *hash)
{
return (*hash = *hash * (guint)1664525 + (guint)1013904223) / (gdouble)4294967296.0;
}
static void
search_box (gint s,
gint t,
gdouble x,
gdouble y,
Context *context)
{
guint hash;
gint i, n;
hash = philox ((guint)s, (guint)t, context->seed);
n = poisson[hash >> 24];
for (i = 0 ; i < n ; i += 1)
{
gdouble delta_x, delta_y, d;
gint j, k;
/* Calculate the distance to each feature point. */
delta_x = s + lcg (&hash) - x;
delta_y = t + lcg (&hash) - y;
if (context->shape == 2)
d = delta_x * delta_x + delta_y * delta_y;
else if (context->shape == 1)
d = fabs (delta_x) + fabs (delta_y);
else
d = pow (fabs (delta_x), context->shape) +
pow (fabs (delta_y), context->shape);
/* Insert it into the list of n closest distances if needed. */
for (j = 0 ; j < context->rank && d > context->closest[j] ; j += 1);
if (j < context->rank)
{
for (k = context->rank - 1 ; k > j ; k -= 1)
{
context->closest[k] = context->closest[k - 1];
}
context->closest[j] = d;
if (j == context->rank - 1)
context->feature = hash;
}
}
}
static double
noise2 (double x,
double y,
Context *context)
{
gdouble d_l, d_r, d_t, d_b, *d_0;
gint s, t, i;
for (i = 0 ; i < context->rank ; context->closest[i] = INFINITY, i += 1);
s = (gint)floor(x);
t = (gint)floor(y);
/* Search the box the point is in. */
search_box (s, t, x, y, context);
d_0 = &context->closest[context->rank - 1];
d_l = x - s; d_l *= d_l;
d_r = 1.0 - x + s; d_r *= d_r;
d_b = y - t; d_b *= d_b;
d_t = 1.0 - y + t; d_t *= d_t;
/* Search adjacent boxes if it is possible for them to contain a
* nearby feature point. */
if (d_l < *d_0)
{
if (d_l + d_b < *d_0)
search_box (s - 1, t - 1, x, y, context);
search_box (s - 1, t, x, y, context);
if (d_l + d_t < *d_0)
search_box (s - 1, t + 1, x, y, context);
}
if (d_b < *d_0)
search_box (s, t - 1, x, y, context);
if (d_t < *d_0)
search_box (s, t + 1, x, y, context);
if (d_r < *d_0)
{
if (d_r + d_b < *d_0)
search_box (s + 1, t - 1, x, y, context);
search_box (s + 1, t, x, y, context);
if (d_r + d_t < *d_0)
search_box (s + 1, t + 1, x, y, context);
}
/* If palettized output is requested return the normalized hash of
* the closest feature point, otherwise return the closest
* distance. */
if (context->palettize)
return (gdouble)context->feature / 4294967295.0;
else
return pow (context->closest[context->rank - 1], 1 / context->shape);
}
static void
prepare (GeglOperation *operation)
{
gegl_operation_set_format (operation, "output", babl_format ("Y float"));
}
static GeglRectangle
get_bounding_box (GeglOperation *operation)
{
return gegl_rectangle_infinite_plane ();
}
static gboolean
cl_process (GeglOperation *operation,
cl_mem out_tex,
const GeglRectangle *roi)
{
GeglChantO *o = GEGL_CHANT_PROPERTIES (operation);
const size_t gbl_size[] = {roi->width, roi->height};
size_t work_group_size;
cl_uint cl_iterations = o->iterations;
cl_int cl_err = 0;
cl_int cl_x_0 = roi->x;
cl_int cl_y_0 = roi->y;
cl_float cl_scale = o->scale / 50.0;
cl_float cl_shape = o->shape;
cl_uint cl_rank = o->rank;
cl_uint cl_seed = o->seed;
cl_int cl_palettize = (cl_int)o->palettize;
if (!cl_data)
{
const char *kernel_name[] = {"kernel_noise", NULL};
cl_data = gegl_cl_compile_and_build (noise_cell_cl_source, kernel_name);
if (!cl_data)
return TRUE;
}
cl_err = gegl_cl_set_kernel_args (cl_data->kernel[0],
sizeof(cl_mem), &out_tex,
sizeof(cl_int), &cl_x_0,
sizeof(cl_int), &cl_y_0,
sizeof(cl_uint), &cl_iterations,
sizeof(cl_float), &cl_scale,
sizeof(cl_float), &cl_shape,
sizeof(cl_uint), &cl_rank,
sizeof(cl_uint), &cl_seed,
sizeof(cl_int), &cl_palettize,
NULL);
CL_CHECK;
cl_err = gegl_clGetKernelWorkGroupInfo (cl_data->kernel[0],
gegl_cl_get_device (),
CL_KERNEL_WORK_GROUP_SIZE,
sizeof (size_t), &work_group_size,
NULL);
CL_CHECK;
cl_err = gegl_clEnqueueNDRangeKernel (gegl_cl_get_command_queue (),
cl_data->kernel[0], 2,
NULL, gbl_size, NULL,
0, NULL, NULL);
CL_CHECK;
cl_err = gegl_clFinish (gegl_cl_get_command_queue ());
CL_CHECK;
return FALSE;
error:
return TRUE;