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 2006 Øyvind Kolås <pippin@gimp.org> 17 */ 18 19 20 #include "config.h" 21 #include <glib/gi18n-lib.h> 22 #include <stdlib.h> 23 24 #ifdef GEGL_PROPERTIES 25 26 property_int (x, _("Width"), 16) 27 description (_("Horizontal width of cells pixels")) 28 value_range (1, G_MAXINT) 29 ui_range (1, 256) 30 ui_gamma (1.5) 31 ui_meta ("unit", "pixel-distance") 32 ui_meta ("axis", "x") 33 34 property_int (y, _("Height"), 16) 35 description (_("Vertical width of cells pixels")) 36 value_range (1, G_MAXINT) 37 ui_range (1, 256) 38 ui_gamma (1.5) 39 ui_meta ("unit", "pixel-distance") 40 ui_meta ("axis", "y") 41 42 property_int (x_offset, _("Offset X"), 0.0) 43 description (_("Horizontal offset (from origin) for start of grid")) 44 ui_range (-128, 128) 45 ui_meta ("unit", "pixel-coordinate") 46 ui_meta ("axis", "x") 47 48 property_int (y_offset, _("Offset Y"), 0) 49 description (_("Vertical offset (from origin) for start of grid")) 50 ui_range (-128, 128) 51 ui_meta ("unit", "pixel-coordinate") 52 ui_meta ("axis", "y") 53 54 property_color (color1, _("Color 1"), "black") 55 description (_("The first cell color")) 56 ui_meta ("role", "color-primary") 57 58 property_color (color2, _("Color 2"), "white") 59 description (_("The second cell color")) 60 ui_meta ("role", "color-secondary") 61 62 property_format (format, _("Babl Format"), NULL) 63 description ( _("The babl format of the output")) 64 65 #else 66 67 #define GEGL_OP_POINT_RENDER 68 #define GEGL_OP_NAME checkerboard 69 #define GEGL_OP_C_SOURCE checkerboard.c 70 71 #include "gegl-op.h" 72 #include <gegl-buffer-cl-iterator.h> 73 #include <../../gegl/gegl-debug.h> 74 75 static void 76 prepare (GeglOperation *operation) 77 { 78 GeglProperties *o = GEGL_PROPERTIES (operation); 79 80 if (o->format) 81 gegl_operation_set_format (operation, "output", o->format); 82 else 83 gegl_operation_set_format (operation, "output", babl_format ("RGBA float")); 84 } 85 86 static GeglRectangle 87 get_bounding_box (GeglOperation *operation) 88 { 89 return gegl_rectangle_infinite_plane (); 90 } 91 92 #define TILE_INDEX(coordinate,stride) \ 93 (((coordinate) >= 0)?\ 94 (coordinate) / (stride):\ 95 ((((coordinate) + 1) /(stride)) - 1)) 96 97 98 #include "opencl/checkerboard.cl.h" 99 static GeglClRunData *cl_data = NULL; 100 101 static gboolean 102 checkerboard_cl_process (GeglOperation *operation, 103 cl_mem out_tex, 104 size_t global_worksize, 105 const GeglRectangle *roi, 106 gint level) 107 { 108 GeglProperties *o = GEGL_PROPERTIES (operation); 109 const Babl *out_format = gegl_operation_get_format (operation, "output"); 110 const size_t gbl_size[2] = {roi->width, roi->height}; 111 const size_t gbl_offs[2] = {roi->x, roi->y}; 112 cl_int cl_err = 0; 113 float color1[4]; 114 float color2[4]; 115 116 if (!cl_data) 117 { 118 const char *kernel_name[] = {"kernel_checkerboard", NULL}; 119 cl_data = gegl_cl_compile_and_build (checkerboard_cl_source, kernel_name); 120 121 if (!cl_data) 122 return TRUE; 123 } 124 125 gegl_color_get_pixel (o->color1, out_format, color1); 126 gegl_color_get_pixel (o->color2, out_format, color2); 127 128 cl_err = gegl_cl_set_kernel_args (cl_data->kernel[0], 129 sizeof(cl_mem), &out_tex, 130 sizeof(color1), &color1, 131 sizeof(color2), &color2, 132 sizeof(cl_int), &o->x, 133 sizeof(cl_int), &o->y, 134 sizeof(cl_int), &o->x_offset, 135 sizeof(cl_int), &o->y_offset, 136 NULL); 137 CL_CHECK; 138 139 cl_err = gegl_clEnqueueNDRangeKernel (gegl_cl_get_command_queue (), 140 cl_data->kernel[0], 2, 141 gbl_offs, gbl_size, NULL, 142 0, NULL, NULL); 143 CL_CHECK; 144 145 return FALSE; 146 error: 147 return TRUE; 148 } 149 150 151 static gboolean 152 checkerboard_process_simple (GeglOperation *operation, 153 void *out_buf, 154 glong n_pixels, 155 const GeglRectangle *roi, 156 gint level) 157 { 158 gint factor = 1 << level; 159 GeglProperties *o = GEGL_PROPERTIES (operation); 160 const Babl *out_format = gegl_operation_get_format (operation, "output"); 161 162 gint pixel_size = babl_format_get_bytes_per_pixel (out_format); 163 guchar *out_pixel = out_buf; 164 void *color1 = alloca(pixel_size); 165 void *color2 = alloca(pixel_size); 166 167 gint x = roi->x; /* initial x */ 168 gint y = roi->y; /* and y coordinates */ 169 170 gegl_color_get_pixel (o->color1, out_format, color1); 171 gegl_color_get_pixel (o->color2, out_format, color2); 172 173 while (n_pixels--) 174 { 175 gint nx,ny; 176 177 if ((x - o->x_offset) < 0) 178 { 179 nx = div (x - o->x_offset + 1, o->x / factor).quot; 180 } 181 else 182 { 183 nx = div (x - o->x_offset, o->x / factor).quot; 184 } 185 186 if ((y - o->y_offset) < 0) 187 { 188 ny = div (y - o->y_offset + 1, o->y / factor).quot; 189 } 190 else 191 { 192 ny = div (y - o->y_offset, o->y / factor).quot; 193 } 194 195 /* shift negative cell indices */ 196 nx -= (x - o->x_offset) < 0 ? 1 : 0; 197 ny -= (y - o->y_offset) < 0 ? 1 : 0; 198 199 if ( (nx+ny) % 2 == 0) 200 memcpy (out_pixel, color1, pixel_size); 201 else 202 memcpy (out_pixel, color2, pixel_size); 203 204 out_pixel += pixel_size; 205 206 /* update x and y coordinates */ 207 x++; 208 if (x>=roi->x + roi->width) 209 { 210 x=roi->x; 211 y++; 212 } 213 } 214 215 return TRUE; 216 } 217 218 static gboolean 219 checkerboard_process (GeglOperation *operation, 220 void *out_buf, 221 glong n_pixels, 222 const GeglRectangle *roi, 223 gint level) 224 { 225 GeglProperties *o = GEGL_PROPERTIES (operation); 226 const Babl *out_format = gegl_operation_get_format (operation, "output"); 227 gint pixel_size = babl_format_get_bytes_per_pixel (out_format); 228 guchar *out_pixel = out_buf; 229 void *color1 = alloca(pixel_size); 230 void *color2 = alloca(pixel_size); 231 gint y; 232 const gint x_min = roi->x - o->x_offset; 233 const gint y_min = roi->y - o->y_offset; 234 const gint x_max = roi->x + roi->width - o->x_offset; 235 const gint y_max = roi->y + roi->height - o->y_offset; 236 237 const gint square_width = o->x; 238 const gint square_height = o->y; 239 240 if (level) 241 return checkerboard_process_simple (operation, out_buf, n_pixels, roi, level); 242 243 gegl_color_get_pixel (o->color1, out_format, color1); 244 gegl_color_get_pixel (o->color2, out_format, color2); 245 246 for (y = y_min; y < y_max; y++) 247 { 248 gint x = x_min; 249 void *cur_color; 250 251 /* Figure out which box we're in */ 252 gint tilex = TILE_INDEX (x, square_width); 253 gint tiley = TILE_INDEX (y, square_height); 254 if ((tilex + tiley) % 2 == 0) 255 cur_color = color1; 256 else 257 cur_color = color2; 258 259 while (x < x_max) 260 { 261 /* Figure out how long this stripe is */ 262 gint count; 263 gint stripe_end = (TILE_INDEX (x, square_width) + 1) * square_width; 264 stripe_end = stripe_end > x_max ? x_max : stripe_end; 265 266 count = stripe_end - x; 267 268 gegl_memset_pattern (out_pixel, cur_color, pixel_size, count); 269 out_pixel += count * pixel_size; 270 x = stripe_end; 271 272 if (cur_color == color1) 273 cur_color = color2; 274 else 275 cur_color = color1; 276 } 277 } 278 279 return TRUE; 280 } 281 282 283 static gboolean 284 operation_source_process (GeglOperation *operation, 285 GeglBuffer *output, 286 const GeglRectangle *result, 287 gint level) 288 { 289 const Babl *out_format = gegl_operation_get_format (operation, "output"); 290 291 if ((result->width > 0) && (result->height > 0)) 292 { 293 GeglBufferIterator *iter; 294 if (gegl_operation_use_opencl (operation) && 295 babl_format_get_n_components (out_format) == 4 && 296 babl_format_get_type (out_format, 0) == babl_type ("float")) 297 { 298 GeglBufferClIterator *cl_iter; 299 gboolean err; 300 301 GEGL_NOTE (GEGL_DEBUG_OPENCL, "GEGL_OPERATION_POINT_RENDER: %s", GEGL_OPERATION_GET_CLASS (operation)->name); 302 303 cl_iter = gegl_buffer_cl_iterator_new (output, result, out_format, GEGL_CL_BUFFER_WRITE); 304 305 while (gegl_buffer_cl_iterator_next (cl_iter, &err) && !err) 306 { 307 err = checkerboard_cl_process (operation, cl_iter->tex[0], cl_iter->size[0], &cl_iter->roi[0], level); 308 309 if (err) 310 { 311 gegl_buffer_cl_iterator_stop (cl_iter); 312 break; 313 } 314 } 315 316 if (err) 317 GEGL_NOTE (GEGL_DEBUG_OPENCL, "Error: %s", GEGL_OPERATION_GET_CLASS (operation)->name); 318 else 319 return TRUE; 320 } 321 322 iter = gegl_buffer_iterator_new (output, result, level, out_format, 323 GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE, 1); 324 325 while (gegl_buffer_iterator_next (iter)) 326 checkerboard_process (operation, iter->items[0].data, iter->length, &iter->items[0].roi, level); 327 } 328 return TRUE; 329 } 330 331 static void 332 gegl_op_class_init (GeglOpClass *klass) 333 { 334 GeglOperationClass *operation_class; 335 GeglOperationSourceClass *source_class; 336 337 operation_class = GEGL_OPERATION_CLASS (klass); 338 source_class = GEGL_OPERATION_SOURCE_CLASS (klass); 339 340 source_class->process = operation_source_process; 341 operation_class->get_bounding_box = get_bounding_box; 342 operation_class->prepare = prepare; 343 operation_class->opencl_support = TRUE; 344 345 gegl_operation_class_set_keys (operation_class, 346 "name", "gegl:checkerboard", 347 "categories", "render", 348 "title", _("Checkerboard"), 349 "reference-hash", "b2f5f85a0ec1de87639c1b0cfcd17fbc", 350 "position-dependent", "true", 351 "description", _("Render a checkerboard pattern"), 352 NULL); 353 } 354 355 #endif 356