1 /* This file is part of GEGL.
2 *
3 * This library 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 * This library 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 this library; if not, see <https://www.gnu.org/licenses/>.
15 *
16 * Copyright 2008,2011,2012,2014,2017 Øyvind Kolås <pippin@gimp.org>
17 * 2013 Daniel Sabo
18 */
19
20 #include "config.h"
21 #include <stdlib.h>
22 #include <string.h>
23 #include <math.h>
24
25 #include <glib-object.h>
26 #include <glib/gprintf.h>
27
28 #include "gegl-buffer.h"
29 #include "gegl-buffer-types.h"
30 #include "gegl-rectangle.h"
31 #include "gegl-buffer-iterator.h"
32 #include "gegl-buffer-iterator-private.h"
33 #include "gegl-buffer-private.h"
34 #include "gegl-tile-storage.h"
35
36 typedef enum {
37 GeglIteratorState_Start,
38 GeglIteratorState_InTile,
39 GeglIteratorState_InRows,
40 GeglIteratorState_Linear,
41 GeglIteratorState_Stop,
42 GeglIteratorState_Invalid,
43 } GeglIteratorState;
44
45 typedef enum {
46 GeglIteratorTileMode_Invalid,
47 GeglIteratorTileMode_DirectTile,
48 GeglIteratorTileMode_LinearTile,
49 GeglIteratorTileMode_GetBuffer,
50 GeglIteratorTileMode_Empty,
51 } GeglIteratorTileMode;
52
53 typedef struct _SubIterState {
54 GeglRectangle full_rect; /* The entire area we are iterating over */
55 GeglBuffer *buffer;
56 GeglAccessMode access_mode;
57 GeglAbyssPolicy abyss_policy;
58 const Babl *format;
59 gint format_bpp;
60 gint alias;
61 GeglIteratorTileMode current_tile_mode;
62 gint row_stride;
63 GeglRectangle real_roi;
64 gint level;
65 gboolean can_discard_data;
66 /* Direct data members */
67 GeglTile *current_tile;
68 /* Indirect data members */
69 gpointer real_data;
70 /* Linear data members */
71 GeglTile *linear_tile;
72 gpointer linear;
73 } SubIterState;
74
75 struct _GeglBufferIteratorPriv
76 {
77 gint num_buffers;
78 GeglIteratorState state;
79 GeglRectangle origin_tile;
80 gint remaining_rows;
81 gint max_slots;
82 SubIterState sub_iter[];
83 /* gint access_order[]; */ /* allocated, but accessed through
84 * get_access_order().
85 */
86 };
87
88 static inline gint *
get_access_order(GeglBufferIterator * iter)89 get_access_order (GeglBufferIterator *iter)
90 {
91 GeglBufferIteratorPriv *priv = iter->priv;
92
93 return (gint *) &priv->sub_iter[priv->max_slots];
94 }
95
96 static inline GeglBufferIterator *
_gegl_buffer_iterator_empty_new(gint max_slots)97 _gegl_buffer_iterator_empty_new (gint max_slots)
98 {
99 GeglBufferIterator *iter = gegl_scratch_alloc0 (
100 sizeof (GeglBufferIterator) +
101 max_slots * sizeof (GeglBufferIteratorItem) +
102 sizeof (GeglBufferIteratorPriv) +
103 max_slots * sizeof (SubIterState) +
104 max_slots * sizeof (gint));
105
106 iter->priv = (GeglBufferIteratorPriv *) (
107 ((guint8 *) iter) +
108 sizeof (GeglBufferIterator) +
109 max_slots * sizeof (GeglBufferIteratorItem));
110
111 iter->priv->max_slots = max_slots;
112
113 iter->priv->num_buffers = 0;
114 iter->priv->state = GeglIteratorState_Start;
115
116 return iter;
117 }
118
119
120 GeglBufferIterator *
gegl_buffer_iterator_empty_new(gint max_slots)121 gegl_buffer_iterator_empty_new (gint max_slots)
122 {
123 return _gegl_buffer_iterator_empty_new (max_slots);
124 }
125
126
127 static inline int
_gegl_buffer_iterator_add(GeglBufferIterator * iter,GeglBuffer * buf,const GeglRectangle * roi,gint level,const Babl * format,GeglAccessMode access_mode,GeglAbyssPolicy abyss_policy)128 _gegl_buffer_iterator_add (GeglBufferIterator *iter,
129 GeglBuffer *buf,
130 const GeglRectangle *roi,
131 gint level,
132 const Babl *format,
133 GeglAccessMode access_mode,
134 GeglAbyssPolicy abyss_policy)
135 {
136 GeglBufferIteratorPriv *priv = iter->priv;
137 int index;
138 SubIterState *sub;
139
140 g_return_val_if_fail (priv->num_buffers < priv->max_slots, 0);
141
142 index = priv->num_buffers++;
143 sub = &priv->sub_iter[index];
144
145 if (!format)
146 format = gegl_buffer_get_format (buf);
147
148 if (!roi)
149 roi = &buf->extent;
150
151 if (index == 0 && (roi->width <= 0 || roi->height <= 0))
152 priv->state = GeglIteratorState_Invalid;
153
154 if (priv->state != GeglIteratorState_Invalid)
155 {
156 sub->buffer = buf;
157 sub->full_rect = *roi;
158
159 sub->access_mode = access_mode;
160 sub->abyss_policy = abyss_policy;
161 sub->current_tile = NULL;
162 sub->real_data = NULL;
163 sub->linear_tile = NULL;
164 sub->format = format;
165 sub->format_bpp = babl_format_get_bytes_per_pixel (format);
166 sub->level = level;
167 sub->can_discard_data = (access_mode & GEGL_ACCESS_READWRITE) ==
168 GEGL_ACCESS_WRITE;
169 sub->alias = -1;
170
171 if (index > 0)
172 {
173 priv->sub_iter[index].full_rect.width = priv->sub_iter[0].full_rect.width;
174 priv->sub_iter[index].full_rect.height = priv->sub_iter[0].full_rect.height;
175 }
176 }
177
178 return index;
179 }
180
181 int
gegl_buffer_iterator_add(GeglBufferIterator * iter,GeglBuffer * buf,const GeglRectangle * roi,gint level,const Babl * format,GeglAccessMode access_mode,GeglAbyssPolicy abyss_policy)182 gegl_buffer_iterator_add (GeglBufferIterator *iter,
183 GeglBuffer *buf,
184 const GeglRectangle *roi,
185 gint level,
186 const Babl *format,
187 GeglAccessMode access_mode,
188 GeglAbyssPolicy abyss_policy)
189 {
190 return _gegl_buffer_iterator_add (iter, buf, roi, level, format, access_mode,
191 abyss_policy);
192 }
193
194
195 GeglBufferIterator *
gegl_buffer_iterator_new(GeglBuffer * buf,const GeglRectangle * roi,gint level,const Babl * format,GeglAccessMode access_mode,GeglAbyssPolicy abyss_policy,gint max_slots)196 gegl_buffer_iterator_new (GeglBuffer *buf,
197 const GeglRectangle *roi,
198 gint level,
199 const Babl *format,
200 GeglAccessMode access_mode,
201 GeglAbyssPolicy abyss_policy,
202 gint max_slots)
203 {
204 GeglBufferIterator *iter = _gegl_buffer_iterator_empty_new (max_slots);
205 _gegl_buffer_iterator_add (iter, buf, roi, level, format,
206 access_mode, abyss_policy);
207
208 return iter;
209 }
210
211 static inline void
release_tile(GeglBufferIterator * iter,int index)212 release_tile (GeglBufferIterator *iter,
213 int index)
214 {
215 GeglBufferIteratorPriv *priv = iter->priv;
216 SubIterState *sub = &priv->sub_iter[index];
217
218 if (sub->current_tile_mode == GeglIteratorTileMode_DirectTile)
219 {
220 if (sub->access_mode & GEGL_ACCESS_WRITE)
221 gegl_tile_unlock_no_void (sub->current_tile);
222 else
223 gegl_tile_read_unlock (sub->current_tile);
224 gegl_tile_unref (sub->current_tile);
225
226 sub->current_tile = NULL;
227 iter->items[index].data = NULL;
228
229 sub->current_tile_mode = GeglIteratorTileMode_Empty;
230 }
231 else if (sub->current_tile_mode == GeglIteratorTileMode_LinearTile)
232 {
233 sub->current_tile = NULL;
234 iter->items[index].data = NULL;
235
236 sub->current_tile_mode = GeglIteratorTileMode_Empty;
237 }
238 else if (sub->current_tile_mode == GeglIteratorTileMode_GetBuffer)
239 {
240 if (sub->access_mode & GEGL_ACCESS_WRITE)
241 {
242 gegl_buffer_set_unlocked_no_notify (sub->buffer,
243 &sub->real_roi,
244 sub->level,
245 sub->format,
246 sub->real_data,
247 GEGL_AUTO_ROWSTRIDE);
248 }
249
250 gegl_scratch_free (sub->real_data);
251 sub->real_data = NULL;
252 iter->items[index].data = NULL;
253
254 sub->current_tile_mode = GeglIteratorTileMode_Empty;
255 }
256 else if (sub->current_tile_mode == GeglIteratorTileMode_Empty)
257 {
258 return;
259 }
260 else
261 {
262 g_warn_if_reached ();
263 }
264 }
265
266 static inline void
retile_subs(GeglBufferIterator * iter,int x,int y)267 retile_subs (GeglBufferIterator *iter,
268 int x,
269 int y)
270 {
271 GeglBufferIteratorPriv *priv = iter->priv;
272 GeglRectangle real_roi;
273 int index;
274
275 int shift_x = priv->origin_tile.x;
276 int shift_y = priv->origin_tile.y;
277
278 int tile_x = gegl_tile_indice (x + shift_x, priv->origin_tile.width);
279 int tile_y = gegl_tile_indice (y + shift_y, priv->origin_tile.height);
280
281 /* Reset tile size */
282 real_roi.x = (tile_x * priv->origin_tile.width) - shift_x;
283 real_roi.y = (tile_y * priv->origin_tile.height) - shift_y;
284 real_roi.width = priv->origin_tile.width;
285 real_roi.height = priv->origin_tile.height;
286
287 /* Trim tile down to the iteration roi */
288 gegl_rectangle_intersect (&iter->items[0].roi, &real_roi, &priv->sub_iter[0].full_rect);
289 priv->sub_iter[0].real_roi = iter->items[0].roi;
290
291 for (index = 1; index < priv->num_buffers; index++)
292 {
293 SubIterState *lead_sub = &priv->sub_iter[0];
294 SubIterState *sub = &priv->sub_iter[index];
295
296 int roi_offset_x = sub->full_rect.x - lead_sub->full_rect.x;
297 int roi_offset_y = sub->full_rect.y - lead_sub->full_rect.y;
298
299 iter->items[index].roi.x = iter->items[0].roi.x + roi_offset_x;
300 iter->items[index].roi.y = iter->items[0].roi.y + roi_offset_y;
301 iter->items[index].roi.width = iter->items[0].roi.width;
302 iter->items[index].roi.height = iter->items[0].roi.height;
303 sub->real_roi = iter->items[index].roi;
304 }
305 }
306
307 static inline gboolean
initialize_rects(GeglBufferIterator * iter)308 initialize_rects (GeglBufferIterator *iter)
309 {
310 GeglBufferIteratorPriv *priv = iter->priv;
311 SubIterState *sub = &priv->sub_iter[0];
312
313 retile_subs (iter, sub->full_rect.x, sub->full_rect.y);
314
315 return TRUE;
316 }
317
318 static inline gboolean
increment_rects(GeglBufferIterator * iter)319 increment_rects (GeglBufferIterator *iter)
320 {
321 GeglBufferIteratorPriv *priv = iter->priv;
322 SubIterState *sub = &priv->sub_iter[0];
323
324 /* Next tile in row */
325 int x = iter->items[0].roi.x + iter->items[0].roi.width;
326 int y = iter->items[0].roi.y;
327
328 if (x >= sub->full_rect.x + sub->full_rect.width)
329 {
330 /* Next row */
331 x = sub->full_rect.x;
332 y += iter->items[0].roi.height;
333
334 if (y >= sub->full_rect.y + sub->full_rect.height)
335 {
336 /* All done */
337 return FALSE;
338 }
339 }
340
341 retile_subs (iter, x, y);
342
343 return TRUE;
344 }
345
346 static inline void
get_tile(GeglBufferIterator * iter,int index)347 get_tile (GeglBufferIterator *iter,
348 int index)
349 {
350 GeglBufferIteratorPriv *priv = iter->priv;
351 SubIterState *sub = &priv->sub_iter[index];
352
353 GeglBuffer *buf = priv->sub_iter[index].buffer;
354
355 if (sub->linear_tile)
356 {
357 sub->current_tile = sub->linear_tile;
358
359 sub->real_roi = buf->extent;
360
361 sub->current_tile_mode = GeglIteratorTileMode_LinearTile;
362 }
363 else
364 {
365 int shift_x = buf->shift_x;
366 int shift_y = buf->shift_y;
367
368 int tile_width = buf->tile_width;
369 int tile_height = buf->tile_height;
370
371 int tile_x = gegl_tile_indice (iter->items[index].roi.x + shift_x, tile_width);
372 int tile_y = gegl_tile_indice (iter->items[index].roi.y + shift_y, tile_height);
373
374 sub->real_roi.x = (tile_x * tile_width) - shift_x;
375 sub->real_roi.y = (tile_y * tile_height) - shift_y;
376 sub->real_roi.width = tile_width;
377 sub->real_roi.height = tile_height;
378
379 g_rec_mutex_lock (&buf->tile_storage->mutex);
380
381 sub->current_tile = gegl_tile_handler_get_tile (
382 (GeglTileHandler *) buf,
383 tile_x, tile_y, sub->level,
384 ! (sub->can_discard_data &&
385 gegl_rectangle_contains (&sub->full_rect, &sub->real_roi)));
386
387 g_rec_mutex_unlock (&buf->tile_storage->mutex);
388
389 if (sub->access_mode & GEGL_ACCESS_WRITE)
390 gegl_tile_lock (sub->current_tile);
391 else
392 gegl_tile_read_lock (sub->current_tile);
393
394 sub->current_tile_mode = GeglIteratorTileMode_DirectTile;
395 }
396
397 sub->row_stride = buf->tile_width * sub->format_bpp;
398
399 iter->items[index].data = gegl_tile_get_data (sub->current_tile);
400 }
401
402 static inline double
level_to_scale(int level)403 level_to_scale (int level)
404 {
405 return level?1.0/(1<<level):1.0;
406 }
407
408 static inline void
get_indirect(GeglBufferIterator * iter,int index)409 get_indirect (GeglBufferIterator *iter,
410 int index)
411 {
412 GeglBufferIteratorPriv *priv = iter->priv;
413 SubIterState *sub = &priv->sub_iter[index];
414
415 sub->real_data = gegl_scratch_alloc (sub->format_bpp *
416 sub->real_roi.width *
417 sub->real_roi.height);
418
419 if (sub->access_mode & GEGL_ACCESS_READ)
420 {
421 gegl_buffer_get_unlocked (sub->buffer, level_to_scale (sub->level), &sub->real_roi, sub->format, sub->real_data,
422 GEGL_AUTO_ROWSTRIDE, sub->abyss_policy);
423 }
424
425 sub->row_stride = sub->real_roi.width * sub->format_bpp;
426
427 iter->items[index].data = sub->real_data;
428 sub->current_tile_mode = GeglIteratorTileMode_GetBuffer;
429 }
430
431 static inline gboolean
needs_indirect_read(GeglBufferIterator * iter,int index)432 needs_indirect_read (GeglBufferIterator *iter,
433 int index)
434 {
435 GeglBufferIteratorPriv *priv = iter->priv;
436 SubIterState *sub = &priv->sub_iter[index];
437
438 if (sub->access_mode & GEGL_ITERATOR_INCOMPATIBLE)
439 return TRUE;
440
441 /* Needs abyss generation */
442 if (!gegl_rectangle_contains (&sub->buffer->abyss, &iter->items[index].roi))
443 return TRUE;
444
445 return FALSE;
446 }
447
448 static inline gboolean
needs_rows(GeglBufferIterator * iter,int index)449 needs_rows (GeglBufferIterator *iter,
450 int index)
451 {
452 GeglBufferIteratorPriv *priv = iter->priv;
453 SubIterState *sub = &priv->sub_iter[index];
454
455 if (sub->current_tile_mode == GeglIteratorTileMode_GetBuffer)
456 return FALSE;
457
458 if (iter->items[index].roi.width != sub->buffer->tile_width ||
459 iter->items[index].roi.height != sub->buffer->tile_height)
460 return TRUE;
461
462 return FALSE;
463 }
464
465 /* Do the final setup of the iter struct */
466 static inline void
prepare_iteration(GeglBufferIterator * iter)467 prepare_iteration (GeglBufferIterator *iter)
468 {
469 GeglBufferIteratorPriv *priv = iter->priv;
470 gint *access_order = get_access_order (iter);
471 gint origin_offset_x;
472 gint origin_offset_y;
473 gint i;
474
475 /* Set up the origin tile */
476 /* FIXME: Pick the most compatable buffer, not just the first */
477 {
478 GeglBuffer *buf = priv->sub_iter[0].buffer;
479
480 priv->origin_tile.x = buf->shift_x;
481 priv->origin_tile.y = buf->shift_y;
482 priv->origin_tile.width = buf->tile_width;
483 priv->origin_tile.height = buf->tile_height;
484
485 origin_offset_x = buf->shift_x + priv->sub_iter[0].full_rect.x;
486 origin_offset_y = buf->shift_y + priv->sub_iter[0].full_rect.y;
487 }
488
489 /* Set up access order */
490 {
491 gint i_write = 0;
492 gint i_read = priv->num_buffers - 1;
493 gint index;
494
495 /* Sort the write-access sub-iterators before the read-access ones */
496
497 for (index = 0; index < priv->num_buffers; index++)
498 {
499 SubIterState *sub = &priv->sub_iter[index];
500
501 if (sub->access_mode & GEGL_ACCESS_WRITE)
502 access_order[i_write++] = index;
503 else
504 access_order[i_read--] = index;
505 }
506 }
507
508 for (i = 0; i < priv->num_buffers; i++)
509 {
510 gint index = access_order[i];
511 SubIterState *sub = &priv->sub_iter[index];
512 GeglBuffer *buf = sub->buffer;
513 gint current_offset_x;
514 gint current_offset_y;
515 gint j;
516
517 gegl_buffer_lock (sub->buffer);
518
519 if (sub->alias >= 0)
520 continue;
521
522 current_offset_x = buf->shift_x + sub->full_rect.x;
523 current_offset_y = buf->shift_y + sub->full_rect.y;
524
525 /* Avoid discarding tile data through a write-only sub-iterator, if
526 * another sub-iterator reads the same tile during the same iteration.
527 * If the two sub-iterators are compatible, make the second sub-iterator
528 * an alias for the first, combining their access mode.
529 */
530 for (j = i + 1; j < priv->num_buffers; j++)
531 {
532 gint index2 = access_order[j];
533 SubIterState *sub2 = &priv->sub_iter[index2];
534 GeglBuffer *buf2 = sub2->buffer;
535 gint current_offset2_x;
536 gint current_offset2_y;
537
538 if (sub2->alias >= 0)
539 continue;
540
541 current_offset2_x = buf2->shift_x + sub2->full_rect.x;
542 current_offset2_y = buf2->shift_y + sub2->full_rect.y;
543
544 if (sub2->level == sub->level &&
545 buf2->tile_storage == buf->tile_storage &&
546 current_offset2_x == current_offset_x &&
547 current_offset2_y == current_offset_y)
548 {
549 if (sub2->access_mode & GEGL_ACCESS_READ)
550 sub->can_discard_data = FALSE;
551
552 if (sub2->format == sub->format &&
553 gegl_rectangle_contains (&sub->buffer->abyss,
554 &sub->full_rect) &&
555 gegl_rectangle_contains (&sub2->buffer->abyss,
556 &sub2->full_rect))
557 {
558 sub->access_mode |= sub2->access_mode;
559
560 sub2->alias = index;
561 }
562 }
563 }
564
565 /* Format converison needed */
566 if (gegl_buffer_get_format (sub->buffer) != sub->format)
567 sub->access_mode |= GEGL_ITERATOR_INCOMPATIBLE;
568 /* Incompatiable tiles */
569 else if ((priv->origin_tile.width != buf->tile_width) ||
570 (priv->origin_tile.height != buf->tile_height) ||
571 (abs(origin_offset_x - current_offset_x) % priv->origin_tile.width != 0) ||
572 (abs(origin_offset_y - current_offset_y) % priv->origin_tile.height != 0))
573 {
574 /* Check if the buffer is a linear buffer */
575 if ((buf->extent.x == -buf->shift_x) &&
576 (buf->extent.y == -buf->shift_y) &&
577 (buf->extent.width == buf->tile_width) &&
578 (buf->extent.height == buf->tile_height))
579 {
580 g_rec_mutex_lock (&buf->tile_storage->mutex);
581
582 sub->linear_tile = gegl_tile_handler_get_tile (
583 (GeglTileHandler *) buf,
584 0, 0, 0,
585 ! (sub->can_discard_data &&
586 gegl_rectangle_contains (&sub->full_rect, &buf->extent)));
587
588 g_rec_mutex_unlock (&buf->tile_storage->mutex);
589
590 if (sub->access_mode & GEGL_ACCESS_WRITE)
591 gegl_tile_lock (sub->linear_tile);
592 else
593 gegl_tile_read_lock (sub->linear_tile);
594 }
595 else
596 sub->access_mode |= GEGL_ITERATOR_INCOMPATIBLE;
597 }
598 }
599 }
600
601 static inline void
load_rects(GeglBufferIterator * iter)602 load_rects (GeglBufferIterator *iter)
603 {
604 GeglBufferIteratorPriv *priv = iter->priv;
605 const gint *access_order = get_access_order (iter);
606 GeglIteratorState next_state = GeglIteratorState_InTile;
607 gint i;
608
609 for (i = 0; i < priv->num_buffers; i++)
610 {
611 gint index = access_order[i];
612 SubIterState *sub = &priv->sub_iter[index];
613
614 if (sub->alias < 0)
615 {
616 if (needs_indirect_read (iter, index))
617 get_indirect (iter, index);
618 else
619 get_tile (iter, index);
620
621 if ((next_state != GeglIteratorState_InRows) &&
622 needs_rows (iter, index))
623 {
624 next_state = GeglIteratorState_InRows;
625 }
626 }
627 else
628 {
629 SubIterState *sub_alias = &priv->sub_iter[sub->alias];
630
631 sub->row_stride = sub_alias->row_stride;
632 sub->real_roi = sub_alias->real_roi;
633
634 iter->items[index].data = iter->items[sub->alias].data;
635 }
636 }
637
638 if (next_state == GeglIteratorState_InRows)
639 {
640 gint index;
641
642 if (iter->items[0].roi.height == 1)
643 next_state = GeglIteratorState_InTile;
644
645 priv->remaining_rows = iter->items[0].roi.height - 1;
646
647 for (index = 0; index < priv->num_buffers; index++)
648 {
649 SubIterState *sub = &priv->sub_iter[index];
650
651 int offset_x = iter->items[index].roi.x - sub->real_roi.x;
652 int offset_y = iter->items[index].roi.y - sub->real_roi.y;
653
654 iter->items[index].data = ((char *)iter->items[index].data) + (offset_y * sub->row_stride + offset_x * sub->format_bpp);
655 iter->items[index].roi.height = 1;
656 }
657 }
658
659 iter->length = iter->items[0].roi.width * iter->items[0].roi.height;
660 priv->state = next_state;
661 }
662
663 static inline void
_gegl_buffer_iterator_stop(GeglBufferIterator * iter)664 _gegl_buffer_iterator_stop (GeglBufferIterator *iter)
665 {
666 GeglBufferIteratorPriv *priv = iter->priv;
667 const gint *access_order = get_access_order (iter);
668 gint i;
669
670 if (priv->state != GeglIteratorState_Invalid)
671 {
672 priv->state = GeglIteratorState_Invalid;
673
674 for (i = priv->num_buffers - 1; i >= 0; i--)
675 {
676 gint index = access_order[i];
677 SubIterState *sub = &priv->sub_iter[index];
678
679 if (sub->alias < 0)
680 {
681 if (sub->current_tile_mode != GeglIteratorTileMode_Empty)
682 release_tile (iter, index);
683
684 if (sub->linear_tile)
685 {
686 if (sub->access_mode & GEGL_ACCESS_WRITE)
687 gegl_tile_unlock_no_void (sub->linear_tile);
688 else
689 gegl_tile_read_unlock (sub->linear_tile);
690 gegl_tile_unref (sub->linear_tile);
691 }
692
693 if (sub->level == 0 &&
694 sub->access_mode & GEGL_ACCESS_WRITE &&
695 ! (sub->access_mode & GEGL_ITERATOR_INCOMPATIBLE))
696 {
697 GeglRectangle damage_rect;
698
699 damage_rect.x = sub->full_rect.x + sub->buffer->shift_x;
700 damage_rect.y = sub->full_rect.y + sub->buffer->shift_y;
701 damage_rect.width = sub->full_rect.width;
702 damage_rect.height = sub->full_rect.height;
703
704 gegl_tile_handler_damage_rect (
705 GEGL_TILE_HANDLER (sub->buffer->tile_storage),
706 &damage_rect);
707 }
708 }
709
710 gegl_buffer_unlock (sub->buffer);
711
712 if ((sub->access_mode & GEGL_ACCESS_WRITE) &&
713 ! (sub->access_mode & GEGL_ITERATOR_NO_NOTIFY))
714 {
715 gegl_buffer_emit_changed_signal (sub->buffer, &sub->full_rect);
716 }
717 }
718 }
719
720 gegl_scratch_free (iter);
721 }
722
723 void
gegl_buffer_iterator_stop(GeglBufferIterator * iter)724 gegl_buffer_iterator_stop (GeglBufferIterator *iter)
725 {
726 _gegl_buffer_iterator_stop (iter);
727 }
728
729
linear_shortcut(GeglBufferIterator * iter)730 static void linear_shortcut (GeglBufferIterator *iter)
731 {
732 GeglBufferIteratorPriv *priv = iter->priv;
733 const gint *access_order = get_access_order (iter);
734 gint index0 = access_order[0];
735 SubIterState *sub0 = &priv->sub_iter[index0];
736 gint i;
737
738 for (i = 0; i < priv->num_buffers; i++)
739 {
740 gint index = access_order[i];
741 SubIterState *sub = &priv->sub_iter[index];
742
743 sub->real_roi = sub0->full_rect;
744 sub->real_roi.x += sub->full_rect.x - sub0->full_rect.x;
745 sub->real_roi.y += sub->full_rect.y - sub0->full_rect.y;
746
747 iter->items[index].roi = sub->real_roi;
748
749 gegl_buffer_lock (sub->buffer);
750
751 if (index == index0)
752 {
753 get_tile (iter, index);
754 }
755 else if (sub->buffer == sub0->buffer && sub->format == sub0->format)
756 {
757 g_print ("!\n");
758 iter->items[index].data = iter->items[index0].data;
759 }
760 else if (sub->buffer->tile_width == sub->buffer->extent.width
761 && sub->buffer->tile_height == sub->buffer->extent.height
762 && sub->buffer->extent.x == iter->items[index].roi.x
763 && sub->buffer->extent.y == iter->items[index].roi.y)
764 {
765 get_tile (iter, index);
766 }
767 else
768 {
769 get_indirect (iter, index);
770 }
771 }
772
773 iter->length = iter->items[0].roi.width * iter->items[0].roi.height;
774 priv->state = GeglIteratorState_Stop; /* quit on next iterator_next */
775 }
776
777 gboolean
gegl_buffer_iterator_next(GeglBufferIterator * iter)778 gegl_buffer_iterator_next (GeglBufferIterator *iter)
779 {
780 GeglBufferIteratorPriv *priv = iter->priv;
781 const gint *access_order = get_access_order (iter);
782
783 if (priv->state == GeglIteratorState_Start)
784 {
785 gint index0 = access_order[0];
786 SubIterState *sub0 = &priv->sub_iter[index0];
787 GeglBuffer *primary = sub0->buffer;
788 gint index;
789
790 if (primary->tile_width == primary->extent.width
791 && primary->tile_height == primary->extent.height
792 && sub0->full_rect.width == primary->tile_width
793 && sub0->full_rect.height == primary->tile_height
794 && sub0->full_rect.x == primary->extent.x
795 && sub0->full_rect.y == primary->extent.y
796 && primary->shift_x == 0
797 && primary->shift_y == 0
798 && FALSE) /* XXX: conditions are not strict enough, GIMPs TIFF
799 plug-in fails; but GEGLs buffer test suite passes
800
801 XXX: still? */
802 {
803 if (gegl_buffer_ext_flush)
804 for (index = 0; index < priv->num_buffers; index++)
805 {
806 SubIterState *sub = &priv->sub_iter[index];
807 gegl_buffer_ext_flush (sub->buffer, &sub->full_rect);
808 }
809 linear_shortcut (iter);
810 return TRUE;
811 }
812
813 prepare_iteration (iter);
814
815 if (gegl_buffer_ext_flush)
816 for (index = 0; index < priv->num_buffers; index++)
817 {
818 SubIterState *sub = &priv->sub_iter[index];
819 gegl_buffer_ext_flush (sub->buffer, &sub->full_rect);
820 }
821
822 initialize_rects (iter);
823
824 load_rects (iter);
825
826 return TRUE;
827 }
828 else if (priv->state == GeglIteratorState_InRows)
829 {
830 gint index;
831
832 for (index = 0; index < priv->num_buffers; index++)
833 {
834 iter->items[index].data = ((char *)iter->items[index].data) + priv->sub_iter[index].row_stride;
835 iter->items[index].roi.y += 1;
836 }
837
838 priv->remaining_rows -= 1;
839
840 if (priv->remaining_rows == 0)
841 priv->state = GeglIteratorState_InTile;
842
843 return TRUE;
844 }
845 else if (priv->state == GeglIteratorState_InTile)
846 {
847 gint i;
848
849 for (i = priv->num_buffers - 1; i >= 0; i--)
850 {
851 gint index = access_order[i];
852 SubIterState *sub = &priv->sub_iter[index];
853
854 if (sub->alias < 0)
855 release_tile (iter, index);
856 }
857
858 if (increment_rects (iter) == FALSE)
859 {
860 _gegl_buffer_iterator_stop (iter);
861 return FALSE;
862 }
863
864 load_rects (iter);
865
866 return TRUE;
867 }
868 else
869 {
870 _gegl_buffer_iterator_stop (iter);
871 return FALSE;
872 }
873 }
874