[gegl/newiter: 3/4] iterator: new state machine iterator
- From: Daniel Sabo <daniels src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gegl/newiter: 3/4] iterator: new state machine iterator
- Date: Tue, 10 Sep 2013 18:49:26 +0000 (UTC)
commit 5231b17c852875cef4b06d28ea0350595c89567e
Author: Daniel Sabo <DanielSabo gmail com>
Date: Fri Aug 30 05:08:12 2013 -0700
iterator: new state machine iterator
gegl/buffer/gegl-buffer-access.c | 26 +
gegl/buffer/gegl-buffer-iterator-private.h | 2 -
gegl/buffer/gegl-buffer-iterator.c | 912 ++++++++++++++--------------
gegl/buffer/gegl-buffer-iterator.h | 22 +-
gegl/gegl-init.c | 1 -
5 files changed, 487 insertions(+), 476 deletions(-)
---
diff --git a/gegl/buffer/gegl-buffer-access.c b/gegl/buffer/gegl-buffer-access.c
index 2abbc51..752b063 100644
--- a/gegl/buffer/gegl-buffer-access.c
+++ b/gegl/buffer/gegl-buffer-access.c
@@ -2118,3 +2118,29 @@ gegl_buffer_dup (GeglBuffer *buffer)
return new_buffer;
}
+/*
+ * check whether iterations on two buffers starting from the given coordinates with
+ * the same width and height would be able to run parallell.
+ */
+gboolean gegl_buffer_scan_compatible (GeglBuffer *bufferA,
+ gint xA,
+ gint yA,
+ GeglBuffer *bufferB,
+ gint xB,
+ gint yB)
+{
+ if (bufferA->tile_storage->tile_width !=
+ bufferB->tile_storage->tile_width)
+ return FALSE;
+ if (bufferA->tile_storage->tile_height !=
+ bufferB->tile_storage->tile_height)
+ return FALSE;
+ if ( (abs((bufferA->shift_x+xA) - (bufferB->shift_x+xB))
+ % bufferA->tile_storage->tile_width) != 0)
+ return FALSE;
+ if ( (abs((bufferA->shift_y+yA) - (bufferB->shift_y+yB))
+ % bufferA->tile_storage->tile_height) != 0)
+ return FALSE;
+ return TRUE;
+}
+
diff --git a/gegl/buffer/gegl-buffer-iterator-private.h b/gegl/buffer/gegl-buffer-iterator-private.h
index fba012b..fd84246 100644
--- a/gegl/buffer/gegl-buffer-iterator-private.h
+++ b/gegl/buffer/gegl-buffer-iterator-private.h
@@ -19,6 +19,4 @@
#ifndef __GEGL_BUFFER_ITERATOR_PRIVATE_H__
#define __GEGL_BUFFER_ITERATOR_PRIVATE_H__
-void _gegl_buffer_iterator_cleanup (void);
-
#endif
diff --git a/gegl/buffer/gegl-buffer-iterator.c b/gegl/buffer/gegl-buffer-iterator.c
index 4874934..fdfda20 100644
--- a/gegl/buffer/gegl-buffer-iterator.c
+++ b/gegl/buffer/gegl-buffer-iterator.c
@@ -14,6 +14,7 @@
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*
* Copyright 2008 Øyvind Kolås <pippin gimp org>
+ * 2013 Daniel Sabo
*/
#include "config.h"
@@ -30,574 +31,549 @@
#include "gegl-buffer-iterator.h"
#include "gegl-buffer-iterator-private.h"
#include "gegl-buffer-private.h"
-#include "gegl-tile-storage.h"
-#include "gegl-utils.h"
-
#include "gegl-buffer-cl-cache.h"
+#include "gegl-utils.h"
-typedef struct GeglBufferTileIterator
+#define GEGL_ITERATOR_INCOMPATIBLE (1 << 2)
+
+typedef enum _GeglIteratorState {
+ GeglIteratorState_Start,
+ GeglIteratorState_InTile,
+ GeglIteratorState_InRows,
+ GeglIteratorState_Invalid,
+} GeglIteratorState;
+
+typedef enum _GeglIteratorTileMode {
+ 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;
+ unsigned int flags;
+ GeglAbyssPolicy abyss_policy;
+ const Babl *format;
+ gint format_bpp;
+ GeglIteratorTileMode current_tile_mode;
+ gint row_stride;
+ GeglRectangle real_roi;
+ /* Direct data members */
+ GeglTile *current_tile;
+ /* Indirect data members */
+ gpointer real_data;
+ /* Linear data members */
+ GeglTile *linear_tile;
+} SubIterState;
+
+struct _GeglBufferIteratorPriv
{
- GeglBuffer *buffer;
- GeglRectangle roi; /* the rectangular region we're iterating over */
- GeglTile *tile; /* current tile */
- gpointer data; /* current tile's data */
-
- gint col; /* the column currently provided for */
- gint row; /* the row currently provided for */
- gboolean write;
- GeglRectangle subrect; /* the subrect that intersected roi */
- gpointer sub_data; /* pointer to the subdata as indicated by subrect */
- gint rowstride; /* rowstride for tile, in bytes */
-
- gint next_col; /* used internally */
- gint next_row; /* used internally */
- gint max_size; /* maximum data buffer needed, in bytes */
- GeglRectangle roi2; /* the rectangular subregion of data
- * in the buffer represented by this scan.
- */
- gboolean same_format;
- gint level;
-} GeglBufferTileIterator;
-
-#define GEGL_BUFFER_SCAN_COMPATIBLE 128 /* should be integrated into enum */
-#define GEGL_BUFFER_FORMAT_COMPATIBLE 256 /* should be integrated into enum */
-
-#define DEBUG_DIRECT 0
-
-typedef struct GeglBufferIterators
+ gint num_buffers;
+ GeglIteratorState state;
+ GeglRectangle origin_tile;
+ gint remaining_rows;
+ SubIterState sub_iter[GEGL_BUFFER_MAX_ITERATORS];
+};
+
+
+GeglBufferIterator *
+gegl_buffer_iterator_empty_new (void)
{
- /* current region of interest */
- gint length; /* length of current data in pixels */
- gpointer data[GEGL_BUFFER_MAX_ITERATORS];
- GeglRectangle roi[GEGL_BUFFER_MAX_ITERATORS]; /* roi of the current data */
-
- /* the following is private: */
- gint iterators;
- gint iteration_no;
- gboolean is_finished;
- GeglRectangle rect [GEGL_BUFFER_MAX_ITERATORS]; /* the region we iterate on. They can be
different from
- each other, but width and height are the same */
- const Babl *format [GEGL_BUFFER_MAX_ITERATORS]; /* The format required for the data */
- GeglBuffer *buffer [GEGL_BUFFER_MAX_ITERATORS]; /* currently a subbuffer of the original, need
to go away */
- guint flags [GEGL_BUFFER_MAX_ITERATORS];
- gpointer buf [GEGL_BUFFER_MAX_ITERATORS]; /* no idea */
- GeglAbyssPolicy abyss_policy [GEGL_BUFFER_MAX_ITERATORS];
- GeglBufferTileIterator i [GEGL_BUFFER_MAX_ITERATORS];
-} GeglBufferIterators;
-
-
-static void gegl_buffer_tile_iterator_init (GeglBufferTileIterator *i,
- GeglBuffer *buffer,
- GeglRectangle roi,
- gboolean write,
- const Babl *format,
- gint level);
-static gboolean gegl_buffer_tile_iterator_next (GeglBufferTileIterator *i);
-
-/*
- * check whether iterations on two buffers starting from the given coordinates with
- * the same width and height would be able to run parallell.
- */
-gboolean gegl_buffer_scan_compatible (GeglBuffer *bufferA,
- gint xA,
- gint yA,
- GeglBuffer *bufferB,
- gint xB,
- gint yB)
+ GeglBufferIterator *iter = g_slice_new (GeglBufferIterator);
+ iter->priv = g_slice_new (GeglBufferIteratorPriv);
+
+ iter->priv->num_buffers = 0;
+ iter->priv->state = GeglIteratorState_Start;
+ return iter;
+}
+
+GeglBufferIterator *
+gegl_buffer_iterator_new (GeglBuffer *buf,
+ const GeglRectangle *roi,
+ gint level,
+ const Babl *format,
+ unsigned int flags,
+ GeglAbyssPolicy abyss_policy)
{
- if (bufferA->tile_storage->tile_width !=
- bufferB->tile_storage->tile_width)
- return FALSE;
- if (bufferA->tile_storage->tile_height !=
- bufferB->tile_storage->tile_height)
- return FALSE;
- if ( (abs((bufferA->shift_x+xA) - (bufferB->shift_x+xB))
- % bufferA->tile_storage->tile_width) != 0)
- return FALSE;
- if ( (abs((bufferA->shift_y+yA) - (bufferB->shift_y+yB))
- % bufferA->tile_storage->tile_height) != 0)
- return FALSE;
- return TRUE;
+ GeglBufferIterator *iter = gegl_buffer_iterator_empty_new ();
+
+ gegl_buffer_iterator_add (iter, buf, roi, level, format, flags, abyss_policy);
+
+ return iter;
}
-static void gegl_buffer_tile_iterator_init (GeglBufferTileIterator *i,
- GeglBuffer *buffer,
- GeglRectangle roi,
- gboolean write,
- const Babl *format,
- gint level)
+int
+gegl_buffer_iterator_add (GeglBufferIterator *iter,
+ GeglBuffer *buf,
+ const GeglRectangle *roi,
+ gint level,
+ const Babl *format,
+ unsigned int flags,
+ GeglAbyssPolicy abyss_policy)
{
- g_assert (i);
- memset (i, 0, sizeof (GeglBufferTileIterator));
-
- i->buffer = buffer;
- i->roi = roi;
- i->level = level;
- i->next_row = 0;
- i->next_col = 0;
- i->tile = NULL;
- i->col = 0;
- i->row = 0;
- i->write = write;
-
- i->max_size = i->buffer->tile_storage->tile_width *
- i->buffer->tile_storage->tile_height;
-
- i->same_format = format == buffer->soft_format;
-
- /* return at the end,. we still want things initialized a bit .. */
- g_return_if_fail (roi.width != 0 && roi.height != 0);
+ GeglBufferIteratorPriv *priv = iter->priv;
+
+ int index = priv->num_buffers++;
+
+ SubIterState *sub = &priv->sub_iter[index];
+
+ g_return_val_if_fail (priv->num_buffers <= GEGL_BUFFER_MAX_ITERATORS, 0);
+
+ if (!format)
+ format = gegl_buffer_get_format (buf);
+
+ if (!roi)
+ roi = &buf->extent;
+
+ sub->buffer = buf;
+ sub->full_rect = *roi;
+ sub->flags = flags;
+ 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->abyss_policy = abyss_policy;
+
+ 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;
+ }
+
+ if (level != 0)
+ g_warning ("iterator level != 0");
+
+ return index;
}
-static gboolean
-gegl_buffer_tile_iterator_next (GeglBufferTileIterator *i)
+static void
+release_tile (GeglBufferIterator *iter,
+ int index)
{
- GeglBuffer *buffer = i->buffer;
- gint tile_width = buffer->tile_storage->tile_width;
- gint tile_height = buffer->tile_storage->tile_height;
- gint buffer_shift_x = buffer->shift_x;
- gint buffer_shift_y = buffer->shift_y;
- gint buffer_x = i->roi.x + buffer_shift_x;
- gint buffer_y = i->roi.y + buffer_shift_y;
+ GeglBufferIteratorPriv *priv = iter->priv;
+ SubIterState *sub = &priv->sub_iter[index];
- if (i->roi.width == 0 || i->roi.height == 0)
- return FALSE;
+ if (sub->current_tile_mode == GeglIteratorTileMode_DirectTile)
+ {
+ if (sub->flags & GEGL_BUFFER_WRITE)
+ gegl_tile_unlock (sub->current_tile);
+ gegl_tile_unref (sub->current_tile);
+
+ sub->current_tile = NULL;
+ iter->data[index] = NULL;
-gulp:
+ sub->current_tile_mode = GeglIteratorTileMode_Empty;
+ }
+ else if (sub->current_tile_mode == GeglIteratorTileMode_LinearTile)
+ {
+ sub->current_tile = NULL;
+ iter->data[index] = NULL;
- /* unref previously held tile */
- if (i->tile)
+ sub->current_tile_mode = GeglIteratorTileMode_Empty;
+ }
+ else if (sub->current_tile_mode == GeglIteratorTileMode_GetBuffer)
{
- if (i->write && i->subrect.width == tile_width && i->same_format)
+ if (sub->flags & GEGL_BUFFER_WRITE)
{
- gegl_tile_unlock (i->tile);
+ gegl_buffer_set_unlocked_no_notify (sub->buffer,
+ &sub->real_roi,
+ sub->format,
+ sub->real_data,
+ GEGL_AUTO_ROWSTRIDE);
}
- gegl_tile_unref (i->tile);
- i->tile = NULL;
- }
- if (i->next_col < i->roi.width)
- { /* return tile on this row */
- gint tiledx = buffer_x + i->next_col;
- gint tiledy = buffer_y + i->next_row;
- gint offsetx = gegl_tile_offset (tiledx, tile_width);
- gint offsety = gegl_tile_offset (tiledy, tile_height);
+ gegl_free (sub->real_data);
+ sub->real_data = NULL;
+ iter->data[index] = NULL;
- {
- i->subrect.x = offsetx;
- i->subrect.y = offsety;
- if (i->roi.width + offsetx - i->next_col < tile_width)
- i->subrect.width = (i->roi.width + offsetx - i->next_col) - offsetx;
- else
- i->subrect.width = tile_width - offsetx;
-
- if (i->roi.height + offsety - i->next_row < tile_height)
- i->subrect.height = (i->roi.height + offsety - i->next_row) - offsety;
- else
- i->subrect.height = tile_height - offsety;
-
- i->tile = gegl_tile_source_get_tile ((GeglTileSource *) (buffer),
- gegl_tile_indice (tiledx, tile_width),
- gegl_tile_indice (tiledy, tile_height),
- 0);
- if (i->write && i->subrect.width == tile_width && i->same_format)
- {
- gegl_tile_lock (i->tile);
- }
- i->data = gegl_tile_get_data (i->tile);
-
- {
- gint bpp = babl_format_get_bytes_per_pixel (i->buffer->soft_format);
- i->rowstride = bpp * tile_width;
- i->sub_data = (guchar*)(i->data) + bpp *
- (i->subrect.y * tile_width + i->subrect.x);
- }
-
- i->col = i->next_col;
- i->row = i->next_row;
- i->next_col += tile_width - offsetx;
-
-
- i->roi2.x = i->roi.x + i->col;
- i->roi2.y = i->roi.y + i->row;
- i->roi2.width = i->subrect.width;
- i->roi2.height = i->subrect.height;
-
- return TRUE;
- }
+ sub->current_tile_mode = GeglIteratorTileMode_Empty;
+ }
+ else if (sub->current_tile_mode == GeglIteratorTileMode_Empty)
+ {
+ return;
}
- else /* move down to next row */
+ else
{
- gint tiledy;
- gint offsety;
+ g_warn_if_reached ();
+ }
+}
- i->row = i->next_row;
- i->col = i->next_col;
+static void
+retile_subs (GeglBufferIterator *iter,
+ int x,
+ int y)
+{
+ GeglBufferIteratorPriv *priv = iter->priv;
+ GeglRectangle real_roi;
+ int index;
- tiledy = buffer_y + i->next_row;
- offsety = gegl_tile_offset (tiledy, tile_height);
+ int shift_x = priv->origin_tile.x;
+ int shift_y = priv->origin_tile.y;
- i->next_row += tile_height - offsety;
- i->next_col=0;
+ 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);
- if (i->next_row < i->roi.height)
- {
- goto gulp; /* return the first tile in the next row */
- }
- return FALSE;
+ /* 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->roi[0], &real_roi, &priv->sub_iter[0].full_rect);
+ priv->sub_iter[0].real_roi = iter->roi[0];
+
+ 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->roi[index].x = iter->roi[0].x + roi_offset_x;
+ iter->roi[index].y = iter->roi[0].y + roi_offset_y;
+ iter->roi[index].width = iter->roi[0].width;
+ iter->roi[index].height = iter->roi[0].height;
+ sub->real_roi = iter->roi[index];
}
- return FALSE;
}
-#if DEBUG_DIRECT
-static glong direct_read = 0;
-static glong direct_write = 0;
-static glong in_direct_read = 0;
-static glong in_direct_write = 0;
-#endif
+static gboolean
+initialize_rects (GeglBufferIterator *iter)
+{
+ GeglBufferIteratorPriv *priv = iter->priv;
+ SubIterState *sub = &priv->sub_iter[0];
+ retile_subs (iter, sub->full_rect.x, sub->full_rect.y);
-gint
-gegl_buffer_iterator_add (GeglBufferIterator *iterator,
- GeglBuffer *buffer,
- const GeglRectangle *roi,
- gint level,
- const Babl *format,
- guint flags,
- GeglAbyssPolicy abyss_policy)
+ return TRUE;
+}
+
+static gboolean
+increment_rects (GeglBufferIterator *iter)
{
- GeglBufferIterators *i = (gpointer)iterator;
- gint self = 0;
- if (i->iterators+1 > GEGL_BUFFER_MAX_ITERATORS)
- {
- g_error ("too many iterators (%i)", i->iterators+1);
- }
+ GeglBufferIteratorPriv *priv = iter->priv;
+ SubIterState *sub = &priv->sub_iter[0];
+
+ /* Next tile in row */
+ int x = iter->roi[0].x + iter->roi[0].width;
+ int y = iter->roi[0].y;
- if (i->iterators == 0) /* for sanity, we zero at init */
+ if (x >= sub->full_rect.x + sub->full_rect.width)
{
- memset (i, 0, sizeof (GeglBufferIterators));
+ /* Next row */
+ x = sub->full_rect.x;
+ y += iter->roi[0].height;
+
+ if (y >= sub->full_rect.y + sub->full_rect.height)
+ {
+ /* All done */
+ return FALSE;
+ }
}
- /* XXX: should assert that the passed in level matches
- * the level of the base iterator.
- */
+ retile_subs (iter, x, y);
- self = i->iterators++;
+ return TRUE;
+}
- if (!roi)
- roi = self==0?&(buffer->extent):&(i->rect[0]);
- i->rect[self]=*roi;
+static void
+get_tile (GeglBufferIterator *iter,
+ int index)
+{
+ GeglBufferIteratorPriv *priv = iter->priv;
+ SubIterState *sub = &priv->sub_iter[index];
- i->buffer[self]= g_object_ref (buffer);
+ GeglBuffer *buf = priv->sub_iter[index].buffer;
- if (format)
- i->format[self]=format;
- else
- i->format[self]=buffer->soft_format;
- i->flags[self]=flags;
+ if (sub->linear_tile)
+ {
+ sub->current_tile = sub->linear_tile;
- i->abyss_policy[self] = abyss_policy;
+ sub->real_roi = buf->extent;
- if (self==0) /* The first buffer which is always scan aligned */
- {
- i->flags[self] |= GEGL_BUFFER_SCAN_COMPATIBLE;
- gegl_buffer_tile_iterator_init (&i->i[self], i->buffer[self], i->rect[self], ((i->flags[self] &
GEGL_BUFFER_WRITE) != 0), i->format[self], level);
+ sub->current_tile_mode = GeglIteratorTileMode_LinearTile;
}
else
{
- /* we make all subsequently added iterators share the width and height of the first one */
- i->rect[self].width = i->rect[0].width;
- i->rect[self].height = i->rect[0].height;
+ int shift_x = buf->shift_x;
+ int shift_y = buf->shift_y;
- if (gegl_buffer_scan_compatible (i->buffer[0], i->rect[0].x, i->rect[0].y,
- i->buffer[self], i->rect[self].x, i->rect[self].y))
- {
- i->flags[self] |= GEGL_BUFFER_SCAN_COMPATIBLE;
- gegl_buffer_tile_iterator_init (&i->i[self], i->buffer[self], i->rect[self], ((i->flags[self] &
GEGL_BUFFER_WRITE) != 0), i->format[self], level);
- }
+ int tile_width = buf->tile_width;
+ int tile_height = buf->tile_height;
+
+ int tile_x = gegl_tile_indice (iter->roi[index].x + shift_x, tile_width);
+ int tile_y = gegl_tile_indice (iter->roi[index].y + shift_y, tile_height);
+
+ sub->current_tile = gegl_tile_source_get_tile ((GeglTileSource *)(buf),
+ tile_x, tile_y, 0);
+
+ if (sub->flags & GEGL_BUFFER_WRITE)
+ gegl_tile_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;
}
- i->buf[self] = NULL;
+ sub->row_stride = buf->tile_width * sub->format_bpp;
+
+ iter->data[index] = gegl_tile_get_data (sub->current_tile);
+}
+
+static void
+get_indirect (GeglBufferIterator *iter,
+ int index)
+{
+ GeglBufferIteratorPriv *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 (i->format[self] == i->buffer[self]->soft_format)
+ if (sub->flags & GEGL_BUFFER_READ)
{
- i->flags[self] |= GEGL_BUFFER_FORMAT_COMPATIBLE;
+ gegl_buffer_get_unlocked (sub->buffer, 1.0, &sub->real_roi, sub->format, sub->real_data,
+ GEGL_AUTO_ROWSTRIDE, sub->abyss_policy);
}
- return self;
+
+ sub->row_stride = sub->real_roi.width * sub->format_bpp;
+
+ iter->data[index] = sub->real_data;
+ sub->current_tile_mode = GeglIteratorTileMode_GetBuffer;
+}
+
+static gboolean
+needs_indirect_read (GeglBufferIterator *iter,
+ int index)
+{
+ GeglBufferIteratorPriv *priv = iter->priv;
+ SubIterState *sub = &priv->sub_iter[index];
+
+ if (sub->flags & GEGL_ITERATOR_INCOMPATIBLE)
+ return TRUE;
+
+ /* Needs abyss generation */
+ if (!gegl_rectangle_contains (&sub->buffer->extent, &iter->roi[index]))
+ return TRUE;
+
+ return FALSE;
}
-typedef struct BufInfo {
- gint size;
- gint used; /* if this buffer is currently allocated */
- gpointer buf;
-} BufInfo;
+static gboolean
+needs_rows (GeglBufferIterator *iter,
+ int index)
+{
+ GeglBufferIteratorPriv *priv = iter->priv;
+ SubIterState *sub = &priv->sub_iter[index];
+
+ if (sub->current_tile_mode == GeglIteratorTileMode_GetBuffer)
+ return FALSE;
+
+ if (iter->roi[index].width != sub->buffer->tile_width ||
+ iter->roi[index].height != sub->buffer->tile_height)
+ return TRUE;
-static GArray *buf_pool = NULL;
-static GMutex pool_mutex = { 0, };
+ return FALSE;
+}
-static gpointer iterator_buf_pool_get (gint size)
+/* Do the final setup of the iter struct */
+static void
+prepare_iteration (GeglBufferIterator *iter)
{
- gint i;
- g_mutex_lock (&pool_mutex);
+ int index;
+ GeglBufferIteratorPriv *priv = iter->priv;
- if (G_UNLIKELY (!buf_pool))
- {
- buf_pool = g_array_new (TRUE, TRUE, sizeof (BufInfo));
- }
- for (i=0; i<buf_pool->len; i++)
+ /* 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;
+ }
+
+ for (index = 0; index < priv->num_buffers; index++)
{
- BufInfo *info = &g_array_index (buf_pool, BufInfo, i);
- if (info->size >= size && info->used == 0)
+ SubIterState *sub = &priv->sub_iter[index];
+ GeglBuffer *buf = sub->buffer;
+
+ /* Format converison needed */
+ if (gegl_buffer_get_format (sub->buffer) != sub->format)
+ sub->flags |= GEGL_ITERATOR_INCOMPATIBLE;
+
+ /* Incompatable tiles */
+ if ((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))
{
- info->used ++;
- g_mutex_unlock (&pool_mutex);
- return info->buf;
+ /* Check if the buffer is a linear buffer */
+ // (g_object_get_data (G_OBJECT (buf), "is-linear"))
+ 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_tile_source_get_tile ((GeglTileSource *)(sub->buffer), 0, 0, 0);
+
+ if (sub->flags & GEGL_BUFFER_WRITE)
+ gegl_tile_lock (sub->linear_tile);
+ }
+ else
+ sub->flags |= GEGL_ITERATOR_INCOMPATIBLE;
}
+
+ gegl_buffer_lock (sub->buffer);
}
- {
- BufInfo info = {0, 1, NULL};
- info.size = size;
- info.buf = gegl_malloc (size);
- g_array_append_val (buf_pool, info);
- g_mutex_unlock (&pool_mutex);
- return info.buf;
- }
}
-static void iterator_buf_pool_release (gpointer buf)
+static void
+load_rects (GeglBufferIterator *iter)
{
- gint i;
- g_mutex_lock (&pool_mutex);
- for (i=0; i<buf_pool->len; i++)
+ GeglBufferIteratorPriv *priv = iter->priv;
+ GeglIteratorState next_state = GeglIteratorState_InTile;
+ int index;
+
+ for (index = 0; index < priv->num_buffers; index++)
{
- BufInfo *info = &g_array_index (buf_pool, BufInfo, i);
- if (info->buf == buf)
+ if (needs_indirect_read (iter, index))
+ get_indirect (iter, index);
+ else
+ get_tile (iter, index);
+
+ if ((next_state != GeglIteratorState_InRows) && needs_rows (iter, index))
{
- info->used --;
- g_mutex_unlock (&pool_mutex);
- return;
+ next_state = GeglIteratorState_InRows;
}
}
- g_assert (0);
- g_mutex_unlock (&pool_mutex);
-}
-void
-_gegl_buffer_iterator_cleanup (void)
-{
- gint i;
- /* FIXME: is the mutex lock necessary? */
- g_mutex_lock (&pool_mutex);
- if (buf_pool)
+ if (next_state == GeglIteratorState_InRows)
{
- for (i=0; i<buf_pool->len; i++)
+ if (iter->roi[0].height == 1)
+ next_state = GeglIteratorState_InTile;
+
+ priv->remaining_rows = iter->roi[0].height - 1;
+
+ for (index = 0; index < priv->num_buffers; index++)
{
- BufInfo *info = &g_array_index (buf_pool, BufInfo, i);
- gegl_free (info->buf);
+ SubIterState *sub = &priv->sub_iter[index];
+
+ int offset_x = iter->roi[index].x - sub->real_roi.x;
+ int offset_y = iter->roi[index].y - sub->real_roi.y;
+
+ iter->data[index] = ((char *)iter->data[index]) + (offset_y * sub->row_stride + offset_x *
sub->format_bpp);
+ iter->roi[index].height = 1;
}
- g_array_free (buf_pool, TRUE);
- buf_pool = NULL;
}
- g_mutex_unlock (&pool_mutex);
-}
-static void ensure_buf (GeglBufferIterators *i, gint no)
-{
- if (i->buf[no]==NULL)
- i->buf[no] = iterator_buf_pool_get (babl_format_get_bytes_per_pixel (i->format[no]) *
- i->i[0].max_size);
+ iter->length = iter->roi[0].width * iter->roi[0].height;
+ priv->state = next_state;
}
void
-gegl_buffer_iterator_stop (GeglBufferIterator *iterator)
+gegl_buffer_iterator_stop (GeglBufferIterator *iter)
{
- GeglBufferIterators *i = (gpointer)iterator;
- gint no;
- for (no=0; no<i->iterators;no++)
+ int index;
+ GeglBufferIteratorPriv *priv = iter->priv;
+ priv->state = GeglIteratorState_Invalid;
+
+ for (index = 0; index < priv->num_buffers; index++)
{
- gint j;
- gboolean found = FALSE;
- for (j=0; j<no; j++)
- if (i->buffer[no]==i->buffer[j])
- {
- found = TRUE;
- break;
- }
- if (!found) {
- gegl_buffer_unlock (i->buffer[no]);
+ SubIterState *sub = &priv->sub_iter[index];
- if (i->flags[no] & GEGL_BUFFER_WRITE) {
- gegl_buffer_emit_changed_signal(i->buffer[no], &(i->rect[no]));
+ if (sub->current_tile_mode != GeglIteratorTileMode_Empty)
+ release_tile (iter, index);
+
+ if (sub->linear_tile)
+ {
+ if (sub->flags & GEGL_BUFFER_WRITE)
+ gegl_tile_unlock (sub->linear_tile);
+ gegl_tile_unref (sub->linear_tile);
}
- }
- }
+ gegl_buffer_unlock (sub->buffer);
- for (no=0; no<i->iterators; no++)
- {
- if (i->buf[no])
- iterator_buf_pool_release (i->buf[no]);
- i->buf[no]=NULL;
- g_object_unref (i->buffer[no]);
+ if (sub->flags & GEGL_BUFFER_WRITE)
+ gegl_buffer_emit_changed_signal (sub->buffer, &sub->full_rect);
}
-#if DEBUG_DIRECT
- g_print ("%f %f\n", (100.0*direct_read/(in_direct_read+direct_read)),
- 100.0*direct_write/(in_direct_write+direct_write));
-#endif
- i->is_finished = TRUE;
- g_slice_free (GeglBufferIterators, i);
+
+ g_slice_free (GeglBufferIteratorPriv, iter->priv);
+ g_slice_free (GeglBufferIterator, iter);
}
gboolean
-gegl_buffer_iterator_next (GeglBufferIterator *iterator)
+gegl_buffer_iterator_next (GeglBufferIterator *iter)
{
- GeglBufferIterators *i = (gpointer)iterator;
- gboolean result = FALSE;
- gint no;
+ GeglBufferIteratorPriv *priv = iter->priv;
- if (i->is_finished)
- g_error ("%s called on finished buffer iterator", G_STRFUNC);
- if (i->iteration_no == 0)
+ if (priv->state == GeglIteratorState_Start)
{
- for (no=0; no<i->iterators;no++)
- {
- gint j;
- gboolean found = FALSE;
- for (j=0; j<no; j++)
- if (i->buffer[no]==i->buffer[j])
- {
- found = TRUE;
- break;
- }
- if (!found)
- gegl_buffer_lock (i->buffer[no]);
-
- if (gegl_cl_is_accelerated ())
- gegl_buffer_cl_cache_flush (i->buffer[no], &i->rect[no]);
- }
- }
- else
- {
- /* complete pending write work */
- for (no=0; no<i->iterators;no++)
- {
- if (i->flags[no] & GEGL_BUFFER_WRITE)
- {
+ int index;
- if (i->flags[no] & GEGL_BUFFER_SCAN_COMPATIBLE &&
- i->flags[no] & GEGL_BUFFER_FORMAT_COMPATIBLE &&
- i->roi[no].width == i->i[no].buffer->tile_storage->tile_width && (i->flags[no] &
GEGL_BUFFER_FORMAT_COMPATIBLE))
- { /* direct access, don't need to do anything */
-#if DEBUG_DIRECT
- direct_write += i->roi[no].width * i->roi[no].height;
-#endif
- }
- else
- {
-#if DEBUG_DIRECT
- in_direct_write += i->roi[no].width * i->roi[no].height;
-#endif
-
- ensure_buf (i, no);
-
- /* Change notification is done in gegl_buffer_iterator_stop */
- gegl_buffer_set_unlocked_no_notify (i->buffer[no], &(i->roi[no]), i->format[no],
i->buf[no], GEGL_AUTO_ROWSTRIDE); /* XXX: use correct level */
- }
- }
- }
- }
+ prepare_iteration (iter);
- g_assert (i->iterators > 0);
+ 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);
+ }
- /* then we iterate all */
- for (no=0; no<i->iterators;no++)
- {
- if (i->flags[no] & GEGL_BUFFER_SCAN_COMPATIBLE)
- {
- gboolean res;
- res = gegl_buffer_tile_iterator_next (&i->i[no]);
- if (no == 0)
- {
- result = res;
- }
- i->roi[no] = i->i[no].roi2;
+ initialize_rects (iter);
- /* since they were scan compatible this should be true */
- if (res != result)
- {
- g_print ("%i==%i != 0==%i\n", no, res, result);
- }
- g_assert (res == result);
+ load_rects (iter);
- if ((i->flags[no] & GEGL_BUFFER_FORMAT_COMPATIBLE) &&
- i->roi[no].width == i->i[no].buffer->tile_storage->tile_width
- )
- {
- /* direct access */
- i->data[no]=i->i[no].sub_data;
-#if DEBUG_DIRECT
- direct_read += i->roi[no].width * i->roi[no].height;
-#endif
- }
- else
- {
- ensure_buf (i, no);
-
- if (i->flags[no] & GEGL_BUFFER_READ)
- {
- gegl_buffer_get_unlocked (i->buffer[no], 1.0, &(i->roi[no]), i->format[no], i->buf[no],
- GEGL_AUTO_ROWSTRIDE, i->abyss_policy[no]);
- }
-
- i->data[no]=i->buf[no];
-#if DEBUG_DIRECT
- in_direct_read += i->roi[no].width * i->roi[no].height;
-#endif
- }
- }
- else
+ return TRUE;
+ }
+ else if (priv->state == GeglIteratorState_InRows)
+ {
+ int index;
+
+ for (index = 0; index < priv->num_buffers; index++)
{
- /* we copy the roi from iterator 0 */
- i->roi[no] = i->roi[0];
- i->roi[no].x += (i->rect[no].x-i->rect[0].x);
- i->roi[no].y += (i->rect[no].y-i->rect[0].y);
+ iter->data[index] = ((char *)iter->data[index]) + priv->sub_iter[index].row_stride;
+ iter->roi[index].y += 1;
+ }
- ensure_buf (i, no);
+ priv->remaining_rows -= 1;
- if (i->flags[no] & GEGL_BUFFER_READ)
- {
- gegl_buffer_get_unlocked (i->buffer[no], 1.0, &(i->roi[no]), i->format[no], i->buf[no],
- GEGL_AUTO_ROWSTRIDE, i->abyss_policy[no]);
- }
- i->data[no]=i->buf[no];
+ if (priv->remaining_rows == 0)
+ priv->state = GeglIteratorState_InTile;
-#if DEBUG_DIRECT
- in_direct_read += i->roi[no].width * i->roi[no].height;
-#endif
- }
- i->length = i->roi[no].width * i->roi[no].height;
+ return TRUE;
}
+ else if (priv->state == GeglIteratorState_InTile)
+ {
+ int index;
- i->iteration_no++;
+ for (index = 0; index < priv->num_buffers; index++)
+ {
+ release_tile (iter, index);
+ }
- if (result == FALSE)
- gegl_buffer_iterator_stop (iterator);
+ if (increment_rects (iter) == FALSE)
+ {
+ gegl_buffer_iterator_stop (iter);
+ return FALSE;
+ }
- return result;
-}
-
-GeglBufferIterator *
-gegl_buffer_iterator_new (GeglBuffer *buffer,
- const GeglRectangle *roi,
- gint level,
- const Babl *format,
- guint flags,
- GeglAbyssPolicy abyss_policy)
-{
- GeglBufferIterator *i = (gpointer)g_slice_new0 (GeglBufferIterators);
- /* Because the iterator is nulled above, we can forgo explicitly setting
- * i->is_finished to FALSE. */
- gegl_buffer_iterator_add (i, buffer, roi, level, format, flags, abyss_policy);
- return i;
-}
+ load_rects (iter);
+ return TRUE;
+ }
+ else
+ {
+ gegl_buffer_iterator_stop (iter);
+ return FALSE;
+ }
+}
\ No newline at end of file
diff --git a/gegl/buffer/gegl-buffer-iterator.h b/gegl/buffer/gegl-buffer-iterator.h
index 7a671f8..636900f 100644
--- a/gegl/buffer/gegl-buffer-iterator.h
+++ b/gegl/buffer/gegl-buffer-iterator.h
@@ -28,6 +28,8 @@
#define GEGL_BUFFER_WRITE 2
#define GEGL_BUFFER_READWRITE (GEGL_BUFFER_READ|GEGL_BUFFER_WRITE)
+typedef struct _GeglBufferIteratorPriv GeglBufferIteratorPriv;
+
/***
* GeglBufferIterator:
*
@@ -37,13 +39,23 @@
*/
typedef struct GeglBufferIterator
{
- gint length;
- gpointer data[GEGL_BUFFER_MAX_ITERATORS];
- GeglRectangle roi[GEGL_BUFFER_MAX_ITERATORS];
+ gint length;
+ gpointer data[GEGL_BUFFER_MAX_ITERATORS];
+ GeglRectangle roi[GEGL_BUFFER_MAX_ITERATORS];
+ /* Private */
+ GeglBufferIteratorPriv *priv;
} GeglBufferIterator;
/**
+ * gegl_buffer_iterator_empty_new: (skip)
+ * Create a new buffer iterator without adding any buffers.
+ *
+ * Returns: a new buffer iterator.
+ */
+GeglBufferIterator *gegl_buffer_iterator_empty_new (void);
+
+/**
* gegl_buffer_iterator_new: (skip)
* @buffer: a #GeglBuffer
* @roi: the rectangle to iterate over
@@ -97,7 +109,7 @@ gint gegl_buffer_iterator_add (GeglBufferIterator *iterator,
GeglAbyssPolicy repeat_mode);
/**
- * gegl_buffer_iterator_stop:
+ * gegl_buffer_iterator_stop: (skip)
* @iterator: a GeglBufferIterator
*
* Cancels the current iteration, freeing up any temporary resources. The
@@ -106,7 +118,7 @@ gint gegl_buffer_iterator_add (GeglBufferIterator *iterator,
void gegl_buffer_iterator_stop (GeglBufferIterator *iterator);
/**
- * gegl_buffer_iterator_next:
+ * gegl_buffer_iterator_next: (skip)
* @iterator: a #GeglBufferIterator
*
* Do an iteration, this causes a new set of iterator->data[] to become
diff --git a/gegl/gegl-init.c b/gegl/gegl-init.c
index 60a1b20..aa87858 100644
--- a/gegl/gegl-init.c
+++ b/gegl/gegl-init.c
@@ -397,7 +397,6 @@ gegl_exit (void)
gegl_tile_cache_destroy ();
gegl_operation_gtype_cleanup ();
gegl_extension_handler_cleanup ();
- _gegl_buffer_iterator_cleanup ();
if (module_db != NULL)
{
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]