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