1 /* This file is an image processing operation for GEGL
2  *
3  * GEGL is free software; you can redistribute it and/or
4  * modify it under the terms of the GNU Lesser General Public
5  * License as published by the Free Software Foundation; either
6  * version 3 of the License, or (at your option) any later version.
7  *
8  * GEGL is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * Lesser General Public License for more details.
12  *
13  * You should have received a copy of the GNU Lesser General Public
14  * License along with GEGL; if not, see <https://www.gnu.org/licenses/>.
15  *
16  * Copyright 1997 Miles O'Neal <meo@rru.com>  http://www.rru.com/~meo/
17  * Copyright 2012 Maxime Nicco <maxime.nicco@gmail.com>
18  */
19 
20 /*
21  *  HURL Operation
22  *      We just assign a random value at the current pixel
23  */
24 
25 #include "config.h"
26 
27 #include <glib/gi18n-lib.h>
28 
29 #ifdef GEGL_PROPERTIES
30 
31 property_double (pct_random, _("Randomization (%)"), 50.0)
32     value_range (0.0, 100.0)
33 
34 property_int   (repeat, _("Repeat"), 1)
35    value_range (1, 100)
36 
37 property_seed (seed, _("Random seed"), rand)
38 
39 #else
40 
41 #define GEGL_OP_POINT_FILTER
42 #define GEGL_OP_NAME     noise_hurl
43 #define GEGL_OP_C_SOURCE noise-hurl.c
44 
45 #include "gegl-op.h"
46 
47 static void
48 prepare (GeglOperation *operation)
49 {
50   const Babl *space = gegl_operation_get_source_space (operation, "input");
51   const Babl *input_format = gegl_operation_get_source_format (operation, "input");
52   GeglProperties *o        = GEGL_PROPERTIES (operation);
53 
54   gegl_operation_set_format (operation, "input" ,
55                              babl_format_with_space ("R'G'B'A float", space));
56   gegl_operation_set_format (operation, "output",
57                              babl_format_with_space ("R'G'B'A float", space));
58 
59   if (input_format)
60     {
61       const Babl *model = babl_format_get_model (input_format);
62 
63       if (babl_model_is (model, "Y'") ||
64           babl_model_is (model, "Y'A") ||
65           babl_model_is (model, "Y") ||
66           babl_model_is (model, "YA"))
67         o->user_data = (void*)0x1;
68 
69       /* a bit hacky, signaling of data being grayscale data and only
70          temporarily in RGBA - performance could be improved by having
71          dedicated code paths for gray formats.
72        */
73     }
74 }
75 
76 static gboolean
77 process (GeglOperation       *operation,
78          void                *in_buf,
79          void                *out_buf,
80          glong                n_pixels,
81          const GeglRectangle *roi,
82          gint                 level)
83 {
84   GeglProperties *o       = GEGL_PROPERTIES (operation);
85   gfloat         *in_pix  = in_buf;
86   gfloat         *out_pix = out_buf;
87   GeglRectangle  *whole_region;
88   gint            total_size, cnt;
89   gint            x, y;
90 
91   whole_region = gegl_operation_source_get_bounding_box (operation, "input");
92   total_size   = whole_region->width * whole_region->height;
93 
94   for (y = roi->y; y < roi->y + roi->height; y++)
95     for (x = roi->x; x < roi->x + roi->width; x++)
96       {
97         gfloat red, green, blue, alpha;
98         gint   idx = x + whole_region->width * y;
99 
100         red   = in_pix[0];
101         green = in_pix[1];
102         blue  = in_pix[2];
103         alpha = in_pix[3];
104 
105         for (cnt = o->repeat - 1; cnt >= 0; cnt--)
106           {
107             gint n = 4 * (idx + cnt * total_size);
108 
109             if (gegl_random_float_range (o->rand, x, y, 0, n, 0.0, 100.0) <=
110                 o->pct_random)
111               {
112                 if (o->user_data) /* input format was greyscale */
113                 {
114                   red   =
115                   green =
116                   blue  = gegl_random_float (o->rand, x, y, 0, n+3);
117                 }
118                 else
119                 {
120                   red   = gegl_random_float (o->rand, x, y, 0, n+1);
121                   green = gegl_random_float (o->rand, x, y, 0, n+2);
122                   blue  = gegl_random_float (o->rand, x, y, 0, n+3);
123                 }
124                 break;
125               }
126           }
127 
128         out_pix[0] = red;
129         out_pix[1] = green;
130         out_pix[2] = blue;
131         out_pix[3] = alpha;
132 
133         out_pix += 4;
134         in_pix  += 4;
135       }
136 
137   return TRUE;
138 }
139 
140 #include "opencl/gegl-cl.h"
141 #include "opencl/noise-hurl.cl.h"
142 
143 static GeglClRunData *cl_data = NULL;
144 
145 static gboolean
146 cl_process (GeglOperation       *operation,
147             cl_mem              in,
148             cl_mem              out,
149             size_t              global_worksize,
150             const GeglRectangle *roi,
151             gint                level)
152 {
153   GeglProperties    *o          = GEGL_PROPERTIES (operation);
154   GeglRectangle *wr         = gegl_operation_source_get_bounding_box (operation,
155                                                                       "input");
156   cl_int      cl_err           = 0;
157   cl_mem      cl_random_data   = NULL;
158   cl_float    pct_random       = o->pct_random;
159   cl_int      gray             = o->user_data ? 1 : 0;
160   cl_int      x_offset         = roi->x;
161   cl_int      y_offset         = roi->y;
162   cl_int      roi_width        = roi->width;
163   cl_int      wr_width         = wr->width;
164   int         total_size       = wr->width*wr->height;
165   cl_int      offset;
166   int         it;
167   cl_ushort4  rand;
168 
169   gegl_cl_random_get_ushort4 (o->rand, &rand);
170 
171   if (!cl_data)
172   {
173     const char *kernel_name[] ={"cl_noise_hurl", NULL};
174     cl_data = gegl_cl_compile_and_build(noise_hurl_cl_source, kernel_name);
175   }
176 
177   if (!cl_data)
178     return TRUE;
179 
180   {
181   cl_random_data = gegl_cl_load_random_data (&cl_err);
182   CL_CHECK;
183 
184   cl_err = gegl_clEnqueueCopyBuffer (gegl_cl_get_command_queue(),
185                                      in , out , 0 , 0 ,
186                                      global_worksize * sizeof(cl_float4),
187                                      0, NULL, NULL);
188   CL_CHECK;
189 
190   gegl_cl_set_kernel_args (cl_data->kernel[0],
191                            sizeof(cl_mem),   &out,
192                            sizeof(cl_mem),   &cl_random_data,
193                            sizeof(cl_int),   &x_offset,
194                            sizeof(cl_int),   &y_offset,
195                            sizeof(cl_int),   &roi_width,
196                            sizeof(cl_int),   &wr_width,
197                            sizeof(cl_ushort4), &rand,
198                            sizeof(cl_float), &pct_random,
199                            sizeof(cl_int),   &gray,
200                            NULL);
201   CL_CHECK;
202 
203   offset = 0;
204 
205   for(it = 0; it < o->repeat; ++it)
206     {
207       cl_err = gegl_clSetKernelArg (cl_data->kernel[0], 9, sizeof(cl_int),
208                                     (void*)&offset);
209       CL_CHECK;
210       cl_err = gegl_clEnqueueNDRangeKernel (gegl_cl_get_command_queue (),
211                                             cl_data->kernel[0], 1,
212                                             NULL, &global_worksize, NULL,
213                                             0, NULL, NULL);
214       CL_CHECK;
215 
216       offset += total_size;
217     }
218 
219   cl_err = gegl_clFinish (gegl_cl_get_command_queue ());
220   CL_CHECK;
221   }
222 
223   return  FALSE;
224 
225 error:
226   return TRUE;
227 }
228 
229 static void
230 gegl_op_class_init (GeglOpClass *klass)
231 {
232   GeglOperationClass            *operation_class;
233   GeglOperationPointFilterClass *point_filter_class;
234 
235   operation_class    = GEGL_OPERATION_CLASS (klass);
236   point_filter_class = GEGL_OPERATION_POINT_FILTER_CLASS (klass);
237 
238   operation_class->prepare    = prepare;
239   operation_class->opencl_support = TRUE;
240   point_filter_class->process = process;
241   point_filter_class->cl_process = cl_process;
242 
243   gegl_operation_class_set_keys (operation_class,
244     "name",               "gegl:noise-hurl",
245     "title",              _("Randomly Shuffle Pixels"),
246     "categories",         "noise",
247     "position-dependent", "true",
248     "reference-hash",     "ad5a185323d116cfee0e74d3283dde79",
249     "description", _("Completely randomize a fraction of pixels"),
250     NULL);
251 }
252 
253 #endif
254