[gegl] buffer: add new iterator api that can take more buffers



commit a84f1a58e52e41a72cb5f8112f550632bc1ed5cf
Author: Øyvind Kolås <pippin gimp org>
Date:   Mon Jul 23 18:18:29 2018 +0200

    buffer: add new iterator api that can take more buffers
    
    if GEGL_ITERATOR2_API is defined before inclusion of the GEGL
    headers a new iterator API with restructured public struct that
    permits using more buffers is used, all code should be migrated
    over to the new API, before the meaning of the old symbols also
    change to the new state in a couple of releases - and the symbols
    should be adopted again.

 gegl/buffer/Makefile.am             |   2 +
 gegl/buffer/gegl-buffer-iterator.h  |  18 +-
 gegl/buffer/gegl-buffer-iterator2.c | 743 ++++++++++++++++++++++++++++++++++++
 gegl/buffer/gegl-buffer-iterator2.h | 137 +++++++
 4 files changed, 898 insertions(+), 2 deletions(-)
---
diff --git a/gegl/buffer/Makefile.am b/gegl/buffer/Makefile.am
index ff30b9612..2f6422ded 100644
--- a/gegl/buffer/Makefile.am
+++ b/gegl/buffer/Makefile.am
@@ -29,6 +29,7 @@ libbuffer_la_SOURCES = \
     gegl-buffer-access.c       \
     gegl-buffer-index.h                \
     gegl-buffer-iterator.c     \
+    gegl-buffer-iterator2.c    \
     gegl-buffer-linear.c       \
        gegl-buffer-load.c      \
     gegl-buffer-save.c         \
@@ -59,6 +60,7 @@ libbuffer_la_SOURCES = \
     gegl-buffer.h              \
     gegl-buffer-private.h      \
     gegl-buffer-iterator.h     \
+    gegl-buffer-iterator2.h    \
     gegl-buffer-iterator-private.h     \
     gegl-buffer-cl-iterator.h  \
     gegl-buffer-cl-cache.h     \
diff --git a/gegl/buffer/gegl-buffer-iterator.h b/gegl/buffer/gegl-buffer-iterator.h
index fcd3ff525..8ff6f984e 100644
--- a/gegl/buffer/gegl-buffer-iterator.h
+++ b/gegl/buffer/gegl-buffer-iterator.h
@@ -22,12 +22,14 @@
 
 #include "gegl-buffer.h"
 
-#define GEGL_BUFFER_MAX_ITERATORS 6
-
 #define GEGL_BUFFER_READ      GEGL_ACCESS_READ
 #define GEGL_BUFFER_WRITE     GEGL_ACCESS_WRITE
 #define GEGL_BUFFER_READWRITE GEGL_ACCESS_READWRITE
 
+#ifndef GEGL_ITERATOR2_API
+
+#define GEGL_BUFFER_MAX_ITERATORS 6
+
 typedef struct _GeglBufferIteratorPriv GeglBufferIteratorPriv;
 
 /***
@@ -131,6 +133,18 @@ void                 gegl_buffer_iterator_stop  (GeglBufferIterator *iterator);
  */
 gboolean             gegl_buffer_iterator_next (GeglBufferIterator *iterator);
 
+#else
+
+#include <gegl-buffer-iterator2.h>
 
+#define GeglBufferIteratorPriv GeglBufferIterator2Priv
+#define GeglBufferIterator GeglBufferIterator2
+#define gegl_buffer_iterator_empty_new #define gegl_buffer_iterator2_empty_new
+#define gegl_buffer_iterator_new gegl_buffer_iterator2_new
+#define gegl_buffer_iterator_add gegl_buffer_iterator2_add
+#define gegl_buffer_iterator_stop gegl_buffer_iterator2_stop
+#define gegl_buffer_iterator_next gegl_buffer_iterator2_next
+
+#endif
 
 #endif
diff --git a/gegl/buffer/gegl-buffer-iterator2.c b/gegl/buffer/gegl-buffer-iterator2.c
new file mode 100644
index 000000000..27aee57b6
--- /dev/null
+++ b/gegl/buffer/gegl-buffer-iterator2.c
@@ -0,0 +1,743 @@
+/* This file is part of GEGL.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <https://www.gnu.org/licenses/>.
+ *
+ * Copyright 2008,2011,2012,2014,2017 Øyvind Kolås <pippin gimp org>
+ *           2013 Daniel Sabo
+ */
+
+#include "config.h"
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include <glib-object.h>
+#include <glib/gprintf.h>
+
+#include "gegl.h"
+#include "gegl-buffer-types.h"
+#include "gegl-buffer-iterator.h"
+#include "gegl-buffer-iterator2.h"
+#include "gegl-buffer-iterator-private.h"
+#include "gegl-buffer-private.h"
+#include "gegl-buffer-cl-cache.h"
+#include "gegl-config.h"
+
+typedef enum {
+  GeglIteratorState_Start,
+  GeglIteratorState_InTile,
+  GeglIteratorState_InRows,
+  GeglIteratorState_Linear,
+  GeglIteratorState_Stop,
+  GeglIteratorState_Invalid,
+} GeglIteratorState;
+
+typedef enum {
+  GeglIteratorTileMode_Invalid,
+  GeglIteratorTileMode_DirectTile,
+  GeglIteratorTileMode_LinearTile,
+  GeglIteratorTileMode_GetBuffer,
+  GeglIteratorTileMode_Empty,
+} GeglIteratorTileMode;
+
+typedef struct _SubIterState {
+  GeglRectangle        full_rect; /* The entire area we are iterating over */
+  GeglBuffer          *buffer;
+  GeglAccessMode       access_mode;
+  GeglAbyssPolicy      abyss_policy;
+  const Babl          *format;
+  gint                 format_bpp;
+  GeglIteratorTileMode current_tile_mode;
+  gint                 row_stride;
+  GeglRectangle        real_roi;
+  gint                 level;
+  /* Direct data members */
+  GeglTile            *current_tile;
+  /* Indirect data members */
+  gpointer             real_data;
+  /* Linear data members */
+  GeglTile            *linear_tile;
+  gpointer             linear;
+} SubIterState;
+
+struct _GeglBufferIterator2Priv
+{
+  gint              num_buffers;
+  GeglIteratorState state;
+  GeglRectangle     origin_tile;
+  gint              remaining_rows;
+  gint              max_slots;
+  SubIterState      sub_iter[];
+};
+
+static gboolean threaded = TRUE;
+
+static inline GeglBufferIterator2 *
+_gegl_buffer_iterator2_empty_new (gint max_slots)
+{
+  GeglBufferIterator2 *iter = g_malloc0 (sizeof (GeglBufferIterator2) +
+                                         max_slots * sizeof (GeglBufferIterator2Item) +
+                                         sizeof (GeglBufferIterator2Priv) +
+                                         max_slots * sizeof (SubIterState));
+  iter->priv      = (void*)(((char*)iter) + sizeof (GeglBufferIterator2) +
+                                         max_slots * sizeof (GeglBufferIterator2Item));
+
+  iter->priv->max_slots = max_slots;
+
+  iter->priv->num_buffers = 0;
+  iter->priv->state       = GeglIteratorState_Start;
+
+  threaded = gegl_config_threads () > 1;
+
+  return iter;
+}
+
+
+GeglBufferIterator2 *
+gegl_buffer_iterator2_empty_new (gint max_slots)
+{
+  return _gegl_buffer_iterator2_empty_new (max_slots);
+}
+
+
+static inline int
+_gegl_buffer_iterator2_add (GeglBufferIterator2  *iter,
+                          GeglBuffer          *buf,
+                          const GeglRectangle *roi,
+                          gint                 level,
+                          const Babl          *format,
+                          GeglAccessMode       access_mode,
+                          GeglAbyssPolicy      abyss_policy)
+{
+  GeglBufferIterator2Priv *priv = iter->priv;
+  int                     index;
+  SubIterState           *sub;
+
+  g_return_val_if_fail (priv->num_buffers < priv->max_slots, 0);
+
+  index = priv->num_buffers++;
+  sub = &priv->sub_iter[index];
+
+  if (!format)
+    format = gegl_buffer_get_format (buf);
+
+  if (!roi)
+    roi = &buf->extent;
+
+  if (index == 0 && (roi->width <= 0 || roi->height <= 0))
+    priv->state = GeglIteratorState_Invalid;
+
+  if (priv->state != GeglIteratorState_Invalid)
+    {
+      sub->buffer       = buf;
+      sub->full_rect    = *roi;
+
+      sub->access_mode  = access_mode;
+      sub->abyss_policy = abyss_policy;
+      sub->current_tile = NULL;
+      sub->real_data    = NULL;
+      sub->linear_tile  = NULL;
+      sub->format       = format;
+      sub->format_bpp   = babl_format_get_bytes_per_pixel (format);
+      sub->level        = level;
+
+      if (index > 0)
+        {
+          priv->sub_iter[index].full_rect.width  = priv->sub_iter[0].full_rect.width;
+          priv->sub_iter[index].full_rect.height = priv->sub_iter[0].full_rect.height;
+        }
+    }
+
+  return index;
+}
+
+int
+gegl_buffer_iterator2_add (GeglBufferIterator2  *iter,
+                          GeglBuffer          *buf,
+                          const GeglRectangle *roi,
+                          gint                 level,
+                          const Babl          *format,
+                          GeglAccessMode       access_mode,
+                          GeglAbyssPolicy      abyss_policy)
+{
+  return _gegl_buffer_iterator2_add (iter, buf, roi, level, format, access_mode,
+abyss_policy);
+}
+
+
+GeglBufferIterator2 *
+gegl_buffer_iterator2_new (GeglBuffer          *buf,
+                          const GeglRectangle *roi,
+                          gint                 level,
+                          const Babl          *format,
+                          GeglAccessMode       access_mode,
+                          GeglAbyssPolicy      abyss_policy,
+                          gint                 max_slots)
+{
+  GeglBufferIterator2 *iter = _gegl_buffer_iterator2_empty_new (max_slots);
+  _gegl_buffer_iterator2_add (iter, buf, roi, level, format,
+                             access_mode, abyss_policy);
+
+  return iter;
+}
+
+static inline void
+release_tile (GeglBufferIterator2 *iter,
+              int index)
+{
+  GeglBufferIterator2Priv *priv = iter->priv;
+  SubIterState           *sub  = &priv->sub_iter[index];
+
+  if (sub->current_tile_mode == GeglIteratorTileMode_DirectTile)
+    {
+      if (sub->access_mode & GEGL_ACCESS_WRITE)
+        gegl_tile_unlock_no_void (sub->current_tile);
+      else
+        gegl_tile_read_unlock (sub->current_tile);
+      gegl_tile_unref (sub->current_tile);
+
+      sub->current_tile = NULL;
+      iter->items[index].data = NULL;
+
+      sub->current_tile_mode = GeglIteratorTileMode_Empty;
+    }
+  else if (sub->current_tile_mode == GeglIteratorTileMode_LinearTile)
+    {
+      sub->current_tile = NULL;
+      iter->items[index].data = NULL;
+
+      sub->current_tile_mode = GeglIteratorTileMode_Empty;
+    }
+  else if (sub->current_tile_mode == GeglIteratorTileMode_GetBuffer)
+    {
+      if (sub->access_mode & GEGL_ACCESS_WRITE)
+        {
+          gegl_buffer_set_unlocked_no_notify (sub->buffer,
+                                              &sub->real_roi,
+                                              sub->level,
+                                              sub->format,
+                                              sub->real_data,
+                                              GEGL_AUTO_ROWSTRIDE);
+        }
+
+      gegl_free (sub->real_data);
+      sub->real_data = NULL;
+      iter->items[index].data = NULL;
+
+      sub->current_tile_mode = GeglIteratorTileMode_Empty;
+    }
+  else if (sub->current_tile_mode == GeglIteratorTileMode_Empty)
+    {
+      return;
+    }
+  else
+    {
+      g_warn_if_reached ();
+    }
+}
+
+static inline void
+retile_subs (GeglBufferIterator2 *iter,
+             int                 x,
+             int                 y)
+{
+  GeglBufferIterator2Priv *priv = iter->priv;
+  GeglRectangle real_roi;
+  int index;
+
+  int shift_x = priv->origin_tile.x;
+  int shift_y = priv->origin_tile.y;
+
+  int tile_x = gegl_tile_indice (x + shift_x, priv->origin_tile.width);
+  int tile_y = gegl_tile_indice (y + shift_y, priv->origin_tile.height);
+
+  /* Reset tile size */
+  real_roi.x = (tile_x * priv->origin_tile.width)  - shift_x;
+  real_roi.y = (tile_y * priv->origin_tile.height) - shift_y;
+  real_roi.width  = priv->origin_tile.width;
+  real_roi.height = priv->origin_tile.height;
+
+  /* Trim tile down to the iteration roi */
+  gegl_rectangle_intersect (&iter->items[0].roi, &real_roi, &priv->sub_iter[0].full_rect);
+  priv->sub_iter[0].real_roi = iter->items[0].roi;
+
+  for (index = 1; index < priv->num_buffers; index++)
+    {
+      SubIterState *lead_sub = &priv->sub_iter[0];
+      SubIterState *sub = &priv->sub_iter[index];
+
+      int roi_offset_x = sub->full_rect.x - lead_sub->full_rect.x;
+      int roi_offset_y = sub->full_rect.y - lead_sub->full_rect.y;
+
+      iter->items[index].roi.x = iter->items[0].roi.x + roi_offset_x;
+      iter->items[index].roi.y = iter->items[0].roi.y + roi_offset_y;
+      iter->items[index].roi.width  = iter->items[0].roi.width;
+      iter->items[index].roi.height = iter->items[0].roi.height;
+      sub->real_roi = iter->items[index].roi;
+    }
+}
+
+static inline gboolean
+initialize_rects (GeglBufferIterator2 *iter)
+{
+  GeglBufferIterator2Priv *priv = iter->priv;
+  SubIterState           *sub  = &priv->sub_iter[0];
+
+  retile_subs (iter, sub->full_rect.x, sub->full_rect.y);
+
+  return TRUE;
+}
+
+static inline gboolean
+increment_rects (GeglBufferIterator2 *iter)
+{
+  GeglBufferIterator2Priv *priv = iter->priv;
+  SubIterState           *sub  = &priv->sub_iter[0];
+
+  /* Next tile in row */
+  int x = iter->items[0].roi.x + iter->items[0].roi.width;
+  int y = iter->items[0].roi.y;
+
+  if (x >= sub->full_rect.x + sub->full_rect.width)
+    {
+      /* Next row */
+      x  = sub->full_rect.x;
+      y += iter->items[0].roi.height;
+
+      if (y >= sub->full_rect.y + sub->full_rect.height)
+        {
+          /* All done */
+          return FALSE;
+        }
+    }
+
+  retile_subs (iter, x, y);
+
+  return TRUE;
+}
+
+static inline void
+get_tile (GeglBufferIterator2 *iter,
+          int                 index)
+{
+  GeglBufferIterator2Priv *priv = iter->priv;
+  SubIterState           *sub  = &priv->sub_iter[index];
+
+  GeglBuffer *buf = priv->sub_iter[index].buffer;
+
+  if (sub->linear_tile)
+    {
+      sub->current_tile = sub->linear_tile;
+
+      sub->real_roi = buf->extent;
+
+      sub->current_tile_mode = GeglIteratorTileMode_LinearTile;
+    }
+  else
+    {
+      int shift_x = buf->shift_x;
+      int shift_y = buf->shift_y;
+
+      int tile_width  = buf->tile_width;
+      int tile_height = buf->tile_height;
+
+      int tile_x = gegl_tile_indice (iter->items[index].roi.x + shift_x, tile_width);
+      int tile_y = gegl_tile_indice (iter->items[index].roi.y + shift_y, tile_height);
+
+      sub->current_tile = gegl_buffer_get_tile (buf, tile_x, tile_y, sub->level);
+
+      if (sub->access_mode & GEGL_ACCESS_WRITE)
+        gegl_tile_lock (sub->current_tile);
+      else
+        gegl_tile_read_lock (sub->current_tile);
+
+      sub->real_roi.x = (tile_x * tile_width)  - shift_x;
+      sub->real_roi.y = (tile_y * tile_height) - shift_y;
+      sub->real_roi.width  = tile_width;
+      sub->real_roi.height = tile_height;
+
+      sub->current_tile_mode = GeglIteratorTileMode_DirectTile;
+    }
+
+  sub->row_stride = buf->tile_width * sub->format_bpp;
+
+  iter->items[index].data = gegl_tile_get_data (sub->current_tile);
+}
+
+static inline double
+level_to_scale (int level)
+{
+  return level?1.0/(1<<level):1.0;
+}
+
+static inline void
+get_indirect (GeglBufferIterator2 *iter,
+              int        index)
+{
+  GeglBufferIterator2Priv *priv = iter->priv;
+  SubIterState           *sub  = &priv->sub_iter[index];
+
+  sub->real_data = gegl_malloc (sub->format_bpp * sub->real_roi.width * sub->real_roi.height);
+
+  if (sub->access_mode & GEGL_ACCESS_READ)
+    {
+      gegl_buffer_get_unlocked (sub->buffer, level_to_scale (sub->level), &sub->real_roi, sub->format, 
sub->real_data,
+                                GEGL_AUTO_ROWSTRIDE, sub->abyss_policy);
+    }
+
+  sub->row_stride = sub->real_roi.width * sub->format_bpp;
+
+  iter->items[index].data = sub->real_data;
+  sub->current_tile_mode = GeglIteratorTileMode_GetBuffer;
+}
+
+static inline gboolean
+needs_indirect_read (GeglBufferIterator2 *iter,
+                     int        index)
+{
+  GeglBufferIterator2Priv *priv = iter->priv;
+  SubIterState           *sub  = &priv->sub_iter[index];
+
+  if (sub->access_mode & GEGL_ITERATOR_INCOMPATIBLE)
+    return TRUE;
+
+  /* Needs abyss generation */
+  if (!gegl_rectangle_contains (&sub->buffer->abyss, &iter->items[index].roi))
+    return TRUE;
+
+  return FALSE;
+}
+
+static inline gboolean
+needs_rows (GeglBufferIterator2 *iter,
+            int        index)
+{
+  GeglBufferIterator2Priv *priv = iter->priv;
+  SubIterState           *sub  = &priv->sub_iter[index];
+
+  if (sub->current_tile_mode == GeglIteratorTileMode_GetBuffer)
+   return FALSE;
+
+  if (iter->items[index].roi.width  != sub->buffer->tile_width ||
+      iter->items[index].roi.height != sub->buffer->tile_height)
+    return TRUE;
+
+  return FALSE;
+}
+
+/* Do the final setup of the iter struct */
+static inline void
+prepare_iteration (GeglBufferIterator2 *iter)
+{
+  int index;
+  GeglBufferIterator2Priv *priv = iter->priv;
+  gint origin_offset_x;
+  gint origin_offset_y;
+
+  /* Set up the origin tile */
+  /* FIXME: Pick the most compatable buffer, not just the first */
+  {
+    GeglBuffer *buf = priv->sub_iter[0].buffer;
+
+    priv->origin_tile.x      = buf->shift_x;
+    priv->origin_tile.y      = buf->shift_y;
+    priv->origin_tile.width  = buf->tile_width;
+    priv->origin_tile.height = buf->tile_height;
+
+    origin_offset_x = buf->shift_x + priv->sub_iter[0].full_rect.x;
+    origin_offset_y = buf->shift_y + priv->sub_iter[0].full_rect.y;
+  }
+
+  for (index = 0; index < priv->num_buffers; index++)
+    {
+      SubIterState *sub = &priv->sub_iter[index];
+      GeglBuffer *buf   = sub->buffer;
+
+      gint current_offset_x = buf->shift_x + priv->sub_iter[index].full_rect.x;
+      gint current_offset_y = buf->shift_y + priv->sub_iter[index].full_rect.y;
+
+      /* Format converison needed */
+      if (gegl_buffer_get_format (sub->buffer) != sub->format)
+        sub->access_mode |= GEGL_ITERATOR_INCOMPATIBLE;
+      /* Incompatiable tiles */
+      else if ((priv->origin_tile.width  != buf->tile_width) ||
+               (priv->origin_tile.height != buf->tile_height) ||
+               (abs(origin_offset_x - current_offset_x) % priv->origin_tile.width != 0) ||
+               (abs(origin_offset_y - current_offset_y) % priv->origin_tile.height != 0))
+        {
+          /* Check if the buffer is a linear buffer */
+          if ((buf->extent.x      == -buf->shift_x) &&
+              (buf->extent.y      == -buf->shift_y) &&
+              (buf->extent.width  == buf->tile_width) &&
+              (buf->extent.height == buf->tile_height))
+            {
+              sub->linear_tile = gegl_buffer_get_tile (sub->buffer, 0, 0, 0);
+
+              if (sub->access_mode & GEGL_ACCESS_WRITE)
+                gegl_tile_lock (sub->linear_tile);
+              else
+                gegl_tile_read_lock (sub->linear_tile);
+            }
+          else
+            sub->access_mode |= GEGL_ITERATOR_INCOMPATIBLE;
+        }
+
+      gegl_buffer_lock (sub->buffer);
+    }
+}
+
+static inline void
+load_rects (GeglBufferIterator2 *iter)
+{
+  GeglBufferIterator2Priv *priv = iter->priv;
+  GeglIteratorState next_state = GeglIteratorState_InTile;
+  int index;
+
+  for (index = 0; index < priv->num_buffers; index++)
+    {
+      if (needs_indirect_read (iter, index))
+        get_indirect (iter, index);
+      else
+        get_tile (iter, index);
+
+      if ((next_state != GeglIteratorState_InRows) && needs_rows (iter, index))
+        {
+          next_state = GeglIteratorState_InRows;
+        }
+    }
+
+  if (next_state == GeglIteratorState_InRows)
+    {
+      if (iter->items[0].roi.height == 1)
+        next_state = GeglIteratorState_InTile;
+
+      priv->remaining_rows = iter->items[0].roi.height - 1;
+
+      for (index = 0; index < priv->num_buffers; index++)
+        {
+          SubIterState *sub = &priv->sub_iter[index];
+
+          int offset_x = iter->items[index].roi.x - sub->real_roi.x;
+          int offset_y = iter->items[index].roi.y - sub->real_roi.y;
+
+          iter->items[index].data = ((char *)iter->items[index].data) + (offset_y * sub->row_stride + 
offset_x * sub->format_bpp);
+          iter->items[index].roi.height = 1;
+        }
+    }
+
+  iter->length = iter->items[0].roi.width * iter->items[0].roi.height;
+  priv->state  = next_state;
+}
+
+static inline void
+_gegl_buffer_iterator2_stop (GeglBufferIterator2 *iter)
+{
+  int index;
+  GeglBufferIterator2Priv *priv = iter->priv;
+
+  if (priv->state != GeglIteratorState_Invalid)
+    {
+      priv->state = GeglIteratorState_Invalid;
+
+      for (index = 0; index < priv->num_buffers; index++)
+        {
+          SubIterState *sub = &priv->sub_iter[index];
+
+          if (sub->current_tile_mode != GeglIteratorTileMode_Empty)
+            release_tile (iter, index);
+
+          if (sub->linear_tile)
+            {
+              if (sub->access_mode & GEGL_ACCESS_WRITE)
+                gegl_tile_unlock_no_void (sub->linear_tile);
+              else
+                gegl_tile_read_unlock (sub->linear_tile);
+              gegl_tile_unref (sub->linear_tile);
+            }
+
+          if (sub->level == 0                      &&
+              sub->access_mode & GEGL_ACCESS_WRITE &&
+              ! (sub->access_mode & GEGL_ITERATOR_INCOMPATIBLE))
+            {
+              GeglRectangle damage_rect;
+
+              damage_rect.x      = sub->full_rect.x + sub->buffer->shift_x;
+              damage_rect.y      = sub->full_rect.y + sub->buffer->shift_y;
+              damage_rect.width  = sub->full_rect.width;
+              damage_rect.height = sub->full_rect.height;
+
+              gegl_tile_handler_damage_rect (
+                GEGL_TILE_HANDLER (sub->buffer->tile_storage),
+                &damage_rect);
+            }
+
+          gegl_buffer_unlock (sub->buffer);
+
+          if ((sub->access_mode & GEGL_ACCESS_WRITE) &&
+              ! (sub->access_mode & GEGL_ITERATOR_NO_NOTIFY))
+            {
+              gegl_buffer_emit_changed_signal (sub->buffer, &sub->full_rect);
+            }
+        }
+    }
+
+  g_free (iter);
+}
+
+void
+gegl_buffer_iterator2_stop (GeglBufferIterator2 *iter)
+{
+  _gegl_buffer_iterator2_stop (iter);
+}
+
+
+static void linear_shortcut (GeglBufferIterator2 *iter)
+{
+  GeglBufferIterator2Priv *priv = iter->priv;
+  SubIterState *sub0 = &priv->sub_iter[0];
+  int index;
+  int re_use_first[16] = {0,};
+
+  for (index = priv->num_buffers-1; index >=0 ; index--)
+  {
+    SubIterState *sub = &priv->sub_iter[index];
+
+    sub->real_roi    = sub0->full_rect;
+    iter->items[index].roi = sub0->full_rect;
+    iter->length = iter->items[0].roi.width * iter->items[0].roi.height;
+
+    if (priv->sub_iter[0].buffer == sub->buffer && index != 0)
+    {
+      if (sub->format == priv->sub_iter[0].format)
+        re_use_first[index] = 1;
+    }
+
+    if (!re_use_first[index])
+    {
+      gegl_buffer_lock (sub->buffer);
+      if (index == 0)
+        get_tile (iter, index);
+      else
+      {
+        if (sub->buffer->tile_width == sub->buffer->extent.width 
+            && sub->buffer->tile_height == sub->buffer->extent.height
+            && sub->buffer->extent.x == iter->items[index].roi.x
+            && sub->buffer->extent.y == iter->items[index].roi.y)
+        {
+          get_tile (iter, index);
+        }
+        else
+          get_indirect (iter, index);
+      }
+    }
+  }
+  for (index = 1; index < priv->num_buffers; index++)
+  {
+    if (re_use_first[index])
+    {
+      g_print ("!\n");
+      iter->items[index].data = iter->items[0].data;
+    }
+  }
+
+  priv->state = GeglIteratorState_Stop; /* quit on next iterator_next */
+}
+
+gboolean
+gegl_buffer_iterator2_next (GeglBufferIterator2 *iter)
+{
+  GeglBufferIterator2Priv *priv = iter->priv;
+
+  if (priv->state == GeglIteratorState_Start)
+    {
+      int index;
+      GeglBuffer *primary = priv->sub_iter[0].buffer;
+      if (primary->tile_width == primary->extent.width 
+          && primary->tile_height == primary->extent.height 
+          && priv->sub_iter[0].full_rect.width == primary->tile_width 
+          && priv->sub_iter[0].full_rect.height == primary->tile_height
+          && priv->sub_iter[0].full_rect.x == primary->extent.x
+          && priv->sub_iter[0].full_rect.y == primary->extent.y
+          && priv->sub_iter[0].buffer->extent.x == iter->items[0].roi.x
+          && priv->sub_iter[0].buffer->extent.y == iter->items[0].roi.y
+          && FALSE) /* XXX: conditions are not strict enough, GIMPs TIFF
+                       plug-in fails; but GEGLs buffer test suite passes */
+      {
+        if (gegl_cl_is_accelerated ())
+          for (index = 0; index < priv->num_buffers; index++)
+            {
+              SubIterState *sub = &priv->sub_iter[index];
+              gegl_buffer_cl_cache_flush (sub->buffer, &sub->full_rect);
+            }
+        linear_shortcut (iter);
+        return TRUE;
+      }
+
+      prepare_iteration (iter);
+
+      if (gegl_cl_is_accelerated ())
+        for (index = 0; index < priv->num_buffers; index++)
+          {
+            SubIterState *sub = &priv->sub_iter[index];
+            gegl_buffer_cl_cache_flush (sub->buffer, &sub->full_rect);
+          }
+
+      initialize_rects (iter);
+
+      load_rects (iter);
+
+      return TRUE;
+    }
+  else if (priv->state == GeglIteratorState_InRows)
+    {
+      int index;
+
+      for (index = 0; index < priv->num_buffers; index++)
+        {
+          iter->items[index].data   = ((char *)iter->items[index].data) + priv->sub_iter[index].row_stride;
+          iter->items[index].roi.y += 1;
+        }
+
+      priv->remaining_rows -= 1;
+
+      if (priv->remaining_rows == 0)
+        priv->state = GeglIteratorState_InTile;
+
+      return TRUE;
+    }
+  else if (priv->state == GeglIteratorState_InTile)
+    {
+      int index;
+
+      for (index = 0; index < priv->num_buffers; index++)
+        {
+          release_tile (iter, index);
+        }
+
+      if (increment_rects (iter) == FALSE)
+        {
+          _gegl_buffer_iterator2_stop (iter);
+          return FALSE;
+        }
+
+      load_rects (iter);
+
+      return TRUE;
+    }
+  else
+    {
+      _gegl_buffer_iterator2_stop (iter);
+      return FALSE;
+    }
+}
diff --git a/gegl/buffer/gegl-buffer-iterator2.h b/gegl/buffer/gegl-buffer-iterator2.h
new file mode 100644
index 000000000..03ff9f256
--- /dev/null
+++ b/gegl/buffer/gegl-buffer-iterator2.h
@@ -0,0 +1,137 @@
+/* This file is part of GEGL.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <https://www.gnu.org/licenses/>.
+ *
+ * Copyright 2008 Øyvind Kolås <pippin gimp org>
+ *           2013 Daniel Sabo
+ */
+
+#ifndef __GEGL_BUFFER_ITERATOR2_H__
+#define __GEGL_BUFFER_ITERATOR2_H__
+
+#include "gegl-buffer.h"
+
+typedef struct _GeglBufferIterator2Priv GeglBufferIterator2Priv;
+
+/***
+ * GeglBufferIterator:
+ *
+ * GeglBufferIterator allows to iterate over one or more GeglBuffers.
+ * In each iteration the new data is available as a linear chunk of
+ * memory. See gegl_buffer_iterator_new() and gegl_buffer_iterator_next()
+ */
+
+typedef struct GeglBufferIterator2Item
+{
+  gpointer      data;
+  GeglRectangle roi;
+} GeglBufferIterator2Item;
+
+typedef struct GeglBufferIterator2
+{
+  gint           length;
+  GeglBufferIterator2Priv *priv;
+  GeglBufferIterator2Item  items[];
+} GeglBufferIterator2;
+
+
+/**
+ * gegl_buffer_iterator_empty_new: (skip)
+ * Create a new buffer iterator without adding any buffers.
+ *
+ * Returns: a new buffer iterator.
+ */
+GeglBufferIterator2 *gegl_buffer_iterator2_empty_new (int max_slots);
+
+/**
+ * gegl_buffer_iterator2_new: (skip)
+ * @buffer: a #GeglBuffer
+ * @roi: the rectangle to iterate over
+ * @level: the level at which we are iterating, the roi will indicate the
+ * extent at 1:1, x,y,width and height are/(2^level)
+ * @format: the format we want to process this buffers data in, pass 0 to use the buffers format.
+ * @access_mode: whether we need reading or writing to this buffer one of GEGL_BUFFER_READ, 
GEGL_BUFFER_WRITE and GEGL_BUFFER_READWRITE.
+ * @abyss_policy: how request outside the buffer extent are handled.
+ *
+ * Create a new buffer iterator, this buffer will be iterated through
+ * in linear chunks, some chunks might be full tiles the coordinates, see
+ * the documentation of gegl_buffer_iterator_next for how to use it and
+ * destroy it.
+ *
+ * Returns: a new buffer iterator that can be used to iterate through the
+ * buffers pixels.
+ */
+GeglBufferIterator2 * gegl_buffer_iterator2_new  (
+                                                 GeglBuffer          *buffer,
+                                                 const GeglRectangle *roi,
+                                                 gint                 level,
+                                                 const Babl          *format,
+                                                 GeglAccessMode       access_mode,
+                                                 GeglAbyssPolicy      abyss_policy,
+                                                 gint                 max_slots);
+
+
+/**
+ * gegl_buffer_iterator2_add: (skip)
+ * @iterator: a #GeglBufferIterator
+ * @buffer: a #GeglBuffer
+ * @roi: the rectangle to iterate over
+ * @level: the level at which we are iterating, the roi will indicate the
+ * extent at 1:1, x,y,width and height are/(2^level)
+ * @format: the format we want to process this buffers data in, pass 0 to use the buffers format.
+ * @access_mode: whether we need reading or writing to this buffer.
+ * @abyss_policy: how request outside the buffer extent are handled.
+ *
+ * Adds an additional buffer iterator that will be processed in sync with
+ * the original one, if the buffer doesn't align with the other for tile access
+ * the corresponding scans and regions will be serialized automatically using
+ * gegl_buffer_get.
+ *
+ * Returns: an integer handle refering to the indice in the iterator structure
+ * of the added buffer.
+ */
+gint                 gegl_buffer_iterator2_add  (GeglBufferIterator2  *iterator,
+                                                GeglBuffer          *buffer,
+                                                const GeglRectangle *roi,
+                                                gint                 level,
+                                                const Babl          *format,
+                                                GeglAccessMode       access_mode,
+                                                GeglAbyssPolicy      abyss_policy);
+
+/**
+ * gegl_buffer_iterator2_stop: (skip)
+ * @iterator: a GeglBufferIterator2
+ *
+ * Cancels the current iteration, freeing up any temporary resources. The
+ * iterator handle is no longer valid after invoking this function.
+ */
+void                 gegl_buffer_iterator2_stop  (GeglBufferIterator2 *iterator);
+
+/**
+ * gegl_buffer_iterator_next: (skip)
+ * @iterator: a #GeglBufferIterator
+ *
+ * Do an iteration, this causes a new set of iterator->data[] to become
+ * available if there is more data to process. Changed data from a previous
+ * iteration step will also be saved now. When there is no more data to
+ * be processed FALSE will be returned (and the iterator handle is no longer
+ * valid).
+ *
+ * Returns: TRUE if there is more work FALSE if iteration is complete.
+ */
+gboolean             gegl_buffer_iterator2_next (GeglBufferIterator2 *iterator);
+
+
+
+#endif


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]