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