1 /* This file is part of 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 2012 Victor Oliveira (victormatheus@gmail.com)
17 */
18
19 #include "config.h"
20 #include <stdlib.h>
21 #include <string.h>
22 #include <math.h>
23
24 #include <glib-object.h>
25 #include <glib/gprintf.h>
26
27 #include "gegl.h"
28 #include "gegl/gegl-debug.h"
29 #include "gegl-buffer-types.h"
30 #include "gegl-buffer-cl-iterator.h"
31 #include "gegl-buffer-cl-cache.h"
32 #include "gegl-buffer-private.h"
33 #include "gegl-tile-storage.h"
34
35 #include "opencl/gegl-cl.h"
36
37 typedef struct GeglBufferClIterators
38 {
39 /* current region of interest */
40 size_t size [GEGL_CL_BUFFER_MAX_ITERATORS]; /* length of current data in pixels */
41 cl_mem tex [GEGL_CL_BUFFER_MAX_ITERATORS];
42 GeglRectangle roi [GEGL_CL_BUFFER_MAX_ITERATORS];
43
44 /* the following is private: */
45 cl_mem tex_buf [GEGL_CL_BUFFER_MAX_ITERATORS];
46 cl_mem tex_op [GEGL_CL_BUFFER_MAX_ITERATORS];
47
48 /* don't free textures loaded from cache */
49 gboolean tex_buf_from_cache [GEGL_CL_BUFFER_MAX_ITERATORS];
50
51 gint iterators;
52 gint iteration_no;
53 gboolean is_finished;
54
55 guint flags [GEGL_CL_BUFFER_MAX_ITERATORS];
56 gint area [GEGL_CL_BUFFER_MAX_ITERATORS][4];
57
58 GeglRectangle rect [GEGL_CL_BUFFER_MAX_ITERATORS]; /* the region we iterate on. They can be
59 different from each other, but width
60 and height are the same */
61
62 const Babl *format [GEGL_CL_BUFFER_MAX_ITERATORS]; /* The format required for the data */
63 GeglBuffer *buffer [GEGL_CL_BUFFER_MAX_ITERATORS];
64
65 /* GeglBuffer's buffer */
66 size_t buf_cl_format_size [GEGL_CL_BUFFER_MAX_ITERATORS];
67 /* Iterator's format */
68 size_t op_cl_format_size [GEGL_CL_BUFFER_MAX_ITERATORS];
69
70 GeglClColorOp conv [GEGL_CL_BUFFER_MAX_ITERATORS];
71
72 GeglAbyssPolicy abyss_policy [GEGL_CL_BUFFER_MAX_ITERATORS];
73
74 /* total iteration */
75 gint rois;
76 GeglRectangle *roi_all;
77
78 } GeglBufferClIterators;
79
80 gint
gegl_buffer_cl_iterator_add_2(GeglBufferClIterator * iterator,GeglBuffer * buffer,const GeglRectangle * result,const Babl * format,guint flags,gint left,gint right,gint top,gint bottom,GeglAbyssPolicy abyss_policy)81 gegl_buffer_cl_iterator_add_2 (GeglBufferClIterator *iterator,
82 GeglBuffer *buffer,
83 const GeglRectangle *result,
84 const Babl *format,
85 guint flags,
86 gint left,
87 gint right,
88 gint top,
89 gint bottom,
90 GeglAbyssPolicy abyss_policy)
91 {
92 GeglBufferClIterators *i = (gpointer)iterator;
93 gint self = 0;
94 if (i->iterators+1 > GEGL_CL_BUFFER_MAX_ITERATORS)
95 {
96 g_error ("too many iterators (%i)", i->iterators+1);
97 }
98
99 if (i->iterators == 0) /* for sanity, we zero at init */
100 {
101 memset (i, 0, sizeof (GeglBufferClIterators));
102 }
103
104 self = i->iterators++;
105
106 if (!result)
107 result = self==0?&(buffer->extent):&(i->rect[0]);
108 i->rect[self]=*result;
109
110 i->flags[self]=flags;
111
112 i->abyss_policy[self]=abyss_policy;
113 if(flags != GEGL_CL_BUFFER_READ && abyss_policy != GEGL_ABYSS_NONE)
114 g_error ("invalid abyss");
115
116 if (flags == GEGL_CL_BUFFER_WRITE || flags == GEGL_CL_BUFFER_READ)
117 {
118 const Babl *buffer_format = gegl_buffer_get_format (buffer);
119
120 g_assert (buffer);
121
122 i->buffer[self]= g_object_ref (buffer);
123
124 if (format)
125 i->format[self] = format;
126 else
127 i->format[self] = buffer_format;
128
129 if (flags == GEGL_CL_BUFFER_WRITE)
130 i->conv[self] = gegl_cl_color_supported (format, buffer_format);
131 else
132 i->conv[self] = gegl_cl_color_supported (buffer_format, format);
133
134 gegl_cl_color_babl (buffer_format, &i->buf_cl_format_size[self]);
135 gegl_cl_color_babl (format, &i->op_cl_format_size [self]);
136
137 /* alpha, non-alpha & GEGL_ABYSS_NONE */
138 if (babl_format_has_alpha(buffer_format) != babl_format_has_alpha(format) &&
139 abyss_policy == GEGL_ABYSS_NONE &&
140 !gegl_rectangle_contains (gegl_buffer_get_extent (buffer), result))
141 {
142 i->conv[self] = GEGL_CL_COLOR_NOT_SUPPORTED;
143 GEGL_NOTE (GEGL_DEBUG_OPENCL, "Performance warning: not using color conversion "
144 "with OpenCL because abyss depends on alpha");
145 }
146 }
147 else /* GEGL_CL_BUFFER_AUX */
148 {
149 g_assert (buffer == NULL);
150
151 i->buffer[self] = NULL;
152 i->format[self] = NULL;
153 i->conv[self] = -1;
154 i->buf_cl_format_size[self] = SIZE_MAX;
155
156 gegl_cl_color_babl (format, &i->op_cl_format_size [self]);
157 }
158
159 i->area[self][0] = left;
160 i->area[self][1] = right;
161 i->area[self][2] = top;
162 i->area[self][3] = bottom;
163
164 if (flags == GEGL_CL_BUFFER_WRITE
165 && (left > 0 || right > 0 || top > 0 || bottom > 0))
166 g_assert(FALSE);
167
168 if (self!=0)
169 {
170 /* we make all subsequently added iterators share the width and height of the first one */
171 i->rect[self].width = i->rect[0].width;
172 i->rect[self].height = i->rect[0].height;
173 }
174 else
175 {
176 gint x, y, j;
177
178 i->rois = 0;
179 for (y=result->y; y < result->y + result->height; y += gegl_cl_get_iter_height ())
180 for (x=result->x; x < result->x + result->width; x += gegl_cl_get_iter_width ())
181 i->rois++;
182
183 i->iteration_no = 0;
184
185 i->roi_all = g_new0 (GeglRectangle, i->rois);
186
187 j = 0;
188 for (y=0; y < result->height; y += gegl_cl_get_iter_height ())
189 for (x=0; x < result->width; x += gegl_cl_get_iter_width ())
190 {
191 GeglRectangle r = {x, y,
192 MIN(gegl_cl_get_iter_width (), result->width - x),
193 MIN(gegl_cl_get_iter_height (), result->height - y)};
194 i->roi_all[j] = r;
195 j++;
196 }
197 }
198
199 return self;
200 }
201
202 gint
gegl_buffer_cl_iterator_add(GeglBufferClIterator * iterator,GeglBuffer * buffer,const GeglRectangle * roi,const Babl * format,guint flags,GeglAbyssPolicy abyss_policy)203 gegl_buffer_cl_iterator_add (GeglBufferClIterator *iterator,
204 GeglBuffer *buffer,
205 const GeglRectangle *roi,
206 const Babl *format,
207 guint flags,
208 GeglAbyssPolicy abyss_policy)
209 {
210 return gegl_buffer_cl_iterator_add_2 (iterator,
211 buffer, roi,
212 format, flags,
213 0, 0, 0, 0,
214 abyss_policy);
215 }
216
217 gint
gegl_buffer_cl_iterator_add_aux(GeglBufferClIterator * iterator,const GeglRectangle * roi,const Babl * format,gint left,gint right,gint top,gint bottom)218 gegl_buffer_cl_iterator_add_aux (GeglBufferClIterator *iterator,
219 const GeglRectangle *roi,
220 const Babl *format,
221 gint left,
222 gint right,
223 gint top,
224 gint bottom)
225 {
226 return gegl_buffer_cl_iterator_add_2 (iterator,
227 NULL, roi,
228 format, GEGL_CL_BUFFER_AUX,
229 left, right,
230 top, bottom,
231 GEGL_ABYSS_NONE);
232 }
233
234 static void
dealloc_iterator(GeglBufferClIterators * i)235 dealloc_iterator(GeglBufferClIterators *i)
236 {
237 int no;
238
239 for (no=0; no<i->iterators;no++)
240 {
241 if (i->buffer[no])
242 {
243 gint j;
244 gboolean found = FALSE;
245 for (j=0; j<no; j++)
246 if (i->buffer[no]==i->buffer[j])
247 {
248 found = TRUE;
249 break;
250 }
251 if (!found)
252 gegl_buffer_unlock (i->buffer[no]);
253
254 g_object_unref (i->buffer[no]);
255 }
256 }
257
258 g_free (i->roi_all);
259 g_slice_free (GeglBufferClIterators, i);
260 }
261
262 #define OPENCL_USE_CACHE 1
263
264 gboolean
gegl_buffer_cl_iterator_next(GeglBufferClIterator * iterator,gboolean * err)265 gegl_buffer_cl_iterator_next (GeglBufferClIterator *iterator, gboolean *err)
266 {
267 GeglBufferClIterators *i = (gpointer)iterator;
268 gint no;
269 cl_int cl_err = 0;
270 int color_err = 0;
271 gboolean is_finished;
272
273 if (i->is_finished)
274 g_error ("%s called on finished buffer iterator", G_STRFUNC);
275
276 if (i->iteration_no == 0)
277 {
278 for (no=0; no<i->iterators;no++)
279 {
280 if (i->buffer[no])
281 {
282 gint j;
283 gboolean found = FALSE;
284 for (j=0; j<no; j++)
285 if (i->buffer[no]==i->buffer[j])
286 {
287 found = TRUE;
288 break;
289 }
290 if (!found)
291 gegl_buffer_lock (i->buffer[no]);
292
293 if (i->flags[no] == GEGL_CL_BUFFER_WRITE
294 || (i->flags[no] == GEGL_CL_BUFFER_READ
295 && (i->area[no][0] > 0 || i->area[no][1] > 0 || i->area[no][2] > 0 || i->area[no][3] > 0)))
296 {
297 gegl_buffer_cl_cache_flush (i->buffer[no], &i->rect[no]);
298 }
299 }
300 }
301 }
302 else
303 {
304 /* complete pending write work */
305 for (no=0; no<i->iterators;no++)
306 {
307 if (i->flags[no] == GEGL_CL_BUFFER_WRITE)
308 {
309 /* color conversion in the GPU (output) */
310 if (i->conv[no] == GEGL_CL_COLOR_CONVERT)
311 {
312 color_err = gegl_cl_color_conv (i->tex_op[no], i->tex_buf[no], i->size[no],
313 i->format[no], gegl_buffer_get_format (i->buffer[no]));
314 if (color_err) goto error;
315 }
316
317 /* GPU -> CPU */
318 {
319 gpointer data;
320
321 /* tile-ize */
322 if (i->conv[no] == GEGL_CL_COLOR_NOT_SUPPORTED)
323 {
324 data = g_malloc(i->size[no] * i->op_cl_format_size [no]);
325
326 cl_err = gegl_clEnqueueReadBuffer(gegl_cl_get_command_queue(),
327 i->tex_op[no], CL_TRUE,
328 0, i->size[no] * i->op_cl_format_size[no], data,
329 0, NULL, NULL);
330 CL_CHECK;
331
332 /* color conversion using BABL */
333 gegl_buffer_set (i->buffer[no], &i->roi[no], 0, i->format[no], data, GEGL_AUTO_ROWSTRIDE);
334
335 g_free(data);
336 }
337 else
338 #ifdef OPENCL_USE_CACHE
339 {
340 gegl_buffer_cl_cache_new (i->buffer[no], &i->roi[no], i->tex_buf[no]);
341 /* don't release this texture */
342 i->tex_buf[no] = NULL;
343 }
344 #else
345 {
346 data = gegl_clEnqueueMapBuffer(gegl_cl_get_command_queue(), i->tex_buf[no], CL_TRUE,
347 CL_MAP_READ,
348 0, i->size[no] * i->buf_cl_format_size [no],
349 0, NULL, NULL, &cl_err);
350 CL_CHECK;
351
352 /* color conversion using BABL */
353 gegl_buffer_set (i->buffer[no], &i->roi[no], 0, i->format[no], data, GEGL_AUTO_ROWSTRIDE);
354
355 cl_err = gegl_clEnqueueUnmapMemObject (gegl_cl_get_command_queue(), i->tex_buf[no], data,
356 0, NULL, NULL);
357 CL_CHECK;
358 }
359 #endif
360 }
361 }
362 }
363
364 /* Run! */
365 cl_err = gegl_clFinish(gegl_cl_get_command_queue());
366 CL_CHECK;
367
368 for (no=0; no < i->iterators; no++)
369 {
370 if (i->tex_buf_from_cache [no])
371 {
372 gboolean ok = gegl_buffer_cl_cache_release (i->tex_buf[no]);
373 g_assert (ok);
374 }
375
376 if (i->tex_buf[no] && !i->tex_buf_from_cache [no])
377 gegl_clReleaseMemObject (i->tex_buf[no]);
378
379 if (i->tex_op [no])
380 gegl_clReleaseMemObject (i->tex_op [no]);
381
382 i->tex [no] = NULL;
383 i->tex_buf[no] = NULL;
384 i->tex_op [no] = NULL;
385 }
386 }
387
388 g_assert (i->iterators > 0);
389 is_finished = i->is_finished = (i->iteration_no >= i->rois);
390
391 /* then we iterate all */
392 if (!i->is_finished)
393 {
394 for (no=0; no<i->iterators;no++)
395 {
396 {
397 GeglRectangle r = {i->rect[no].x + i->roi_all[i->iteration_no].x - i->area[no][0],
398 i->rect[no].y + i->roi_all[i->iteration_no].y - i->area[no][2],
399 i->roi_all[i->iteration_no].width + i->area[no][0] + i->area[no][1],
400 i->roi_all[i->iteration_no].height + i->area[no][2] + i->area[no][3]};
401 i->roi [no] = r;
402 i->size[no] = r.width * r.height;
403
404 g_assert(i->size[no] > 0);
405 }
406
407 if (i->flags[no] == GEGL_CL_BUFFER_READ)
408 {
409 {
410 gpointer data;
411
412 /* un-tile */
413 switch (i->conv[no])
414 {
415 case GEGL_CL_COLOR_NOT_SUPPORTED:
416
417 {
418 gegl_buffer_cl_cache_flush (i->buffer[no], &i->roi[no]);
419
420 g_assert (i->tex_op[no] == NULL);
421 i->tex_op[no] = gegl_clCreateBuffer (gegl_cl_get_context (),
422 CL_MEM_ALLOC_HOST_PTR | CL_MEM_READ_ONLY,
423 i->size[no] * i->op_cl_format_size [no],
424 NULL, &cl_err);
425 CL_CHECK;
426
427 /* pre-pinned memory */
428 data = gegl_clEnqueueMapBuffer(gegl_cl_get_command_queue(), i->tex_op[no], CL_TRUE,
429 CL_MAP_WRITE,
430 0, i->size[no] * i->op_cl_format_size [no],
431 0, NULL, NULL, &cl_err);
432 CL_CHECK;
433
434 /* color conversion using BABL */
435 gegl_buffer_get (i->buffer[no], &i->roi[no], 1.0, i->format[no], data, GEGL_AUTO_ROWSTRIDE, i->abyss_policy[no]);
436
437 cl_err = gegl_clEnqueueUnmapMemObject (gegl_cl_get_command_queue(), i->tex_op[no], data,
438 0, NULL, NULL);
439 CL_CHECK;
440
441 i->tex[no] = i->tex_op[no];
442
443 break;
444 }
445
446 case GEGL_CL_COLOR_EQUAL:
447
448 {
449 i->tex_buf[no] = gegl_buffer_cl_cache_get (i->buffer[no], &i->roi[no]);
450
451 if (i->tex_buf[no])
452 i->tex_buf_from_cache [no] = TRUE; /* don't free texture from cache */
453 else
454 {
455 gegl_buffer_cl_cache_flush (i->buffer[no], &i->roi[no]);
456
457 g_assert (i->tex_buf[no] == NULL);
458 i->tex_buf[no] = gegl_clCreateBuffer (gegl_cl_get_context (),
459 CL_MEM_ALLOC_HOST_PTR | CL_MEM_READ_ONLY,
460 i->size[no] * i->buf_cl_format_size [no],
461 NULL, &cl_err);
462 CL_CHECK;
463
464 /* pre-pinned memory */
465 data = gegl_clEnqueueMapBuffer(gegl_cl_get_command_queue(), i->tex_buf[no], CL_TRUE,
466 CL_MAP_WRITE,
467 0, i->size[no] * i->buf_cl_format_size [no],
468 0, NULL, NULL, &cl_err);
469 CL_CHECK;
470
471 /* color conversion will be performed in the GPU later */
472 gegl_buffer_get (i->buffer[no], &i->roi[no], 1.0, NULL, data, GEGL_AUTO_ROWSTRIDE, i->abyss_policy[no]);
473
474 cl_err = gegl_clEnqueueUnmapMemObject (gegl_cl_get_command_queue(), i->tex_buf[no], data,
475 0, NULL, NULL);
476 CL_CHECK;
477 }
478
479 i->tex[no] = i->tex_buf[no];
480
481 break;
482 }
483
484 case GEGL_CL_COLOR_CONVERT:
485
486 {
487 i->tex_buf[no] = gegl_buffer_cl_cache_get (i->buffer[no], &i->roi[no]);
488
489 if (i->tex_buf[no])
490 i->tex_buf_from_cache [no] = TRUE; /* don't free texture from cache */
491 else
492 {
493 gegl_buffer_cl_cache_flush (i->buffer[no], &i->roi[no]);
494
495 g_assert (i->tex_buf[no] == NULL);
496 i->tex_buf[no] = gegl_clCreateBuffer (gegl_cl_get_context (),
497 CL_MEM_ALLOC_HOST_PTR | CL_MEM_READ_ONLY,
498 i->size[no] * i->buf_cl_format_size [no],
499 NULL, &cl_err);
500 CL_CHECK;
501
502 /* pre-pinned memory */
503 data = gegl_clEnqueueMapBuffer(gegl_cl_get_command_queue(), i->tex_buf[no], CL_TRUE,
504 CL_MAP_WRITE,
505 0, i->size[no] * i->buf_cl_format_size [no],
506 0, NULL, NULL, &cl_err);
507 CL_CHECK;
508
509 /* color conversion will be performed in the GPU later */
510 gegl_buffer_get (i->buffer[no], &i->roi[no], 1.0, NULL, data, GEGL_AUTO_ROWSTRIDE, i->abyss_policy[no]);
511
512 cl_err = gegl_clEnqueueUnmapMemObject (gegl_cl_get_command_queue(), i->tex_buf[no], data,
513 0, NULL, NULL);
514 CL_CHECK;
515 }
516
517 g_assert (i->tex_op[no] == NULL);
518 i->tex_op[no] = gegl_clCreateBuffer (gegl_cl_get_context (),
519 CL_MEM_READ_WRITE,
520 i->size[no] * i->op_cl_format_size [no],
521 NULL, &cl_err);
522 CL_CHECK;
523
524 /* color conversion in the GPU (input) */
525 g_assert (i->tex_buf[no] && i->tex_op[no]);
526 color_err = gegl_cl_color_conv (i->tex_buf[no], i->tex_op[no], i->size[no],
527 gegl_buffer_get_format (i->buffer[no]), i->format[no]);
528 if (color_err) goto error;
529
530 i->tex[no] = i->tex_op[no];
531
532 break;
533 }
534 }
535 }
536 }
537 else if (i->flags[no] == GEGL_CL_BUFFER_WRITE)
538 {
539 {
540 switch (i->conv[no])
541 {
542 case GEGL_CL_COLOR_NOT_SUPPORTED:
543
544 {
545 g_assert (i->tex_op[no] == NULL);
546 i->tex_op[no] = gegl_clCreateBuffer (gegl_cl_get_context (),
547 CL_MEM_WRITE_ONLY,
548 i->size[no] * i->op_cl_format_size [no],
549 NULL, &cl_err);
550 CL_CHECK;
551
552 i->tex[no] = i->tex_op[no];
553
554 break;
555 }
556
557 case GEGL_CL_COLOR_EQUAL:
558
559 {
560 g_assert (i->tex_buf[no] == NULL);
561 i->tex_buf[no] = gegl_clCreateBuffer (gegl_cl_get_context (),
562 CL_MEM_READ_WRITE, /* cache */
563 i->size[no] * i->buf_cl_format_size [no],
564 NULL, &cl_err);
565 CL_CHECK;
566
567 i->tex[no] = i->tex_buf[no];
568
569 break;
570 }
571
572 case GEGL_CL_COLOR_CONVERT:
573
574 {
575 g_assert (i->tex_buf[no] == NULL);
576 i->tex_buf[no] = gegl_clCreateBuffer (gegl_cl_get_context (),
577 CL_MEM_READ_WRITE, /* cache */
578 i->size[no] * i->buf_cl_format_size [no],
579 NULL, &cl_err);
580 CL_CHECK;
581
582 g_assert (i->tex_op[no] == NULL);
583 i->tex_op[no] = gegl_clCreateBuffer (gegl_cl_get_context (),
584 CL_MEM_READ_WRITE,
585 i->size[no] * i->op_cl_format_size [no],
586 NULL, &cl_err);
587 CL_CHECK;
588
589 i->tex[no] = i->tex_op[no];
590
591 break;
592 }
593 }
594 }
595 }
596 else if (i->flags[no] == GEGL_CL_BUFFER_AUX)
597 {
598 {
599 g_assert (i->tex_op[no] == NULL);
600 i->tex_op[no] = gegl_clCreateBuffer (gegl_cl_get_context (),
601 CL_MEM_READ_WRITE,
602 i->size[no] * i->op_cl_format_size [no],
603 NULL, &cl_err);
604 CL_CHECK;
605
606 i->tex[no] = i->tex_op[no];
607 }
608 }
609 }
610
611 i->iteration_no++;
612 }
613 else /* i->is_finished == TRUE */
614 {
615 dealloc_iterator(i);
616 }
617
618 if (err)
619 *err = FALSE;
620 return !is_finished;
621
622 error:
623 gegl_buffer_cl_iterator_stop ((GeglBufferClIterator *)i);
624
625 if (err)
626 *err = TRUE;
627 return FALSE;
628 }
629
630 void
gegl_buffer_cl_iterator_stop(GeglBufferClIterator * iterator)631 gegl_buffer_cl_iterator_stop (GeglBufferClIterator *iterator)
632 {
633 GeglBufferClIterators *i = (GeglBufferClIterators *)iterator;
634 int no;
635
636 for (no = 0; no < i->iterators; no++)
637 {
638 if (i->tex_buf[no]) gegl_clReleaseMemObject (i->tex_buf[no]);
639 if (i->tex_op [no]) gegl_clReleaseMemObject (i->tex_op [no]);
640
641 i->tex [no] = NULL;
642 i->tex_buf[no] = NULL;
643 i->tex_op [no] = NULL;
644 }
645
646 dealloc_iterator (i);
647 }
648
649 GeglBufferClIterator *
gegl_buffer_cl_iterator_new(GeglBuffer * buffer,const GeglRectangle * roi,const Babl * format,guint flags)650 gegl_buffer_cl_iterator_new (GeglBuffer *buffer,
651 const GeglRectangle *roi,
652 const Babl *format,
653 guint flags)
654 {
655 GeglBufferClIterator *i = (gpointer)g_slice_new0 (GeglBufferClIterators);
656 /* Because the iterator is nulled above, we can forgo explicitly setting
657 * i->is_finished to FALSE. */
658 gegl_buffer_cl_iterator_add (i, buffer, roi, format, flags, GEGL_ABYSS_NONE);
659 return i;
660 }
661