[gegl/soc-2011-warp: 11/25] gegl_buffer_dup: implement copy on write



commit 8ef22b9b9df7927afb9ba0fc37f14cea53c0f0ef
Author: Michael Murà <batolettre gmail com>
Date:   Tue Jul 26 11:22:39 2011 +0200

    gegl_buffer_dup: implement copy on write

 gegl/buffer/gegl-buffer-access.c |  173 +++++++++++++++++++++++++++++++++++++-
 1 files changed, 170 insertions(+), 3 deletions(-)
---
diff --git a/gegl/buffer/gegl-buffer-access.c b/gegl/buffer/gegl-buffer-access.c
index 92e7648..ced9d68 100644
--- a/gegl/buffer/gegl-buffer-access.c
+++ b/gegl/buffer/gegl-buffer-access.c
@@ -1125,6 +1125,153 @@ gegl_buffer_sample_cleanup (GeglBuffer *buffer)
     }
 }
 
+
+typedef struct GeglBufferTileIterator
+{
+  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.
+                            */
+
+} GeglBufferTileIterator;
+
+static void
+gegl_buffer_tile_iterator_init (GeglBufferTileIterator *it,
+                                GeglBuffer             *buffer,
+                                GeglRectangle           roi,
+                                gboolean                write)
+{
+  g_assert (it);
+  memset (it, 0, sizeof (GeglBufferTileIterator));
+
+  if (roi.width == 0 || roi.height == 0)
+    g_error ("eeek");
+
+  it->buffer = buffer;
+  it->roi = roi;
+  it->next_row    = 0;
+  it->next_col = 0;
+  it->tile = NULL;
+  it->col = 0;
+  it->row = 0;
+  it->write = write;
+  it->max_size = it->buffer->tile_storage->tile_width *
+                 it->buffer->tile_storage->tile_height;
+}
+
+static gboolean
+gegl_buffer_tile_iterator_next (GeglBufferTileIterator *it)
+{
+  GeglBuffer *buffer   = it->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       = buffer->extent.x + buffer_shift_x;
+  gint  buffer_y       = buffer->extent.y + buffer_shift_y;
+
+  if (it->roi.width == 0 || it->roi.height == 0)
+    return FALSE;
+
+gulp:
+
+  /* unref previously held tile */
+  if (it->tile)
+    {
+      if (it->write && it->subrect.width == tile_width)
+        {
+          gegl_tile_unlock (it->tile);
+        }
+      gegl_tile_unref (it->tile);
+      it->tile = NULL;
+    }
+
+  if (it->next_col < it->roi.width)
+    { /* return tile on this row */
+      gint tiledx = buffer_x + it->next_col;
+      gint tiledy = buffer_y + it->next_row;
+      gint offsetx = gegl_tile_offset (tiledx, tile_width);
+      gint offsety = gegl_tile_offset (tiledy, tile_height);
+
+      {
+        it->subrect.x = offsetx;
+        it->subrect.y = offsety;
+        if (it->roi.width + offsetx - it->next_col < tile_width)
+          it->subrect.width = (it->roi.width + offsetx - it->next_col) - offsetx;
+        else
+          it->subrect.width = tile_width - offsetx;
+
+        if (it->roi.height + offsety - it->next_row < tile_height)
+          it->subrect.height = (it->roi.height + offsety - it->next_row) - offsety;
+        else
+          it->subrect.height = tile_height - offsety;
+
+        it->tile = gegl_tile_source_get_tile ((GeglTileSource *) (buffer),
+                                              gegl_tile_indice (tiledx, tile_width),
+                                              gegl_tile_indice (tiledy, tile_height),
+                                              0);
+        if (it->write && tile_width==it->subrect.width)
+          {
+            gegl_tile_lock (it->tile);
+          }
+        it->data = gegl_tile_get_data (it->tile);
+
+        {
+          gint bpp = babl_format_get_bytes_per_pixel (it->buffer->format);
+          it->rowstride = bpp * tile_width;
+          it->sub_data = (guchar*)(it->data) + bpp * (it->subrect.y * tile_width + it->subrect.x);
+        }
+
+        it->col = it->next_col;
+        it->row = it->next_row;
+        it->next_col += tile_width - offsetx;
+
+
+        it->roi2.x      = it->roi.x + it->col;
+        it->roi2.y      = it->roi.y + it->row;
+        it->roi2.width  = it->subrect.width;
+        it->roi2.height = it->subrect.height;
+
+        return TRUE;
+      }
+    }
+  else /* move down to next row */
+    {
+      gint tiledy;
+      gint offsety;
+
+      it->row = it->next_row;
+      it->col = it->next_col;
+
+      tiledy = buffer_y + it->next_row;
+      offsety = gegl_tile_offset (tiledy, tile_height);
+
+      it->next_row += tile_height - offsety;
+      it->next_col=0;
+
+      if (it->next_row < it->roi.height)
+        {
+          goto gulp; /* return the first tile in the next row */
+        }
+      return FALSE;
+    }
+  return FALSE;
+}
+
 void
 gegl_buffer_copy (GeglBuffer          *src,
                   const GeglRectangle *src_rect,
@@ -1195,13 +1342,33 @@ gegl_buffer_clear (GeglBuffer          *dst,
 GeglBuffer *
 gegl_buffer_dup (GeglBuffer *buffer)
 {
-  GeglBuffer *new_buffer;
+  GeglBuffer             *new_buffer;
+  GeglBufferTileIterator  it;
+  GeglRectangle           extent;
+  GeglTileSource         *tile_source;
 
   g_return_val_if_fail (GEGL_IS_BUFFER (buffer), NULL);
 
   new_buffer = gegl_buffer_new (gegl_buffer_get_extent (buffer), buffer->format);
-  gegl_buffer_copy (buffer, gegl_buffer_get_extent (buffer),
-                    new_buffer, gegl_buffer_get_extent (buffer));
+  tile_source = GEGL_TILE_SOURCE (new_buffer);
+
+  extent = *gegl_buffer_get_extent (buffer);
+
+  gegl_buffer_tile_iterator_init (&it, buffer, extent, FALSE);
+
+  while (gegl_buffer_tile_iterator_next (&it))
+    {
+      GeglTile *tile;
+      gboolean  success;
+
+      tile = gegl_tile_dup (it.tile);
+
+      success = gegl_tile_source_set_tile (tile_source, tile->x, tile->y, tile->z, tile);
+
+      if (!success)
+        g_print ("Error in inserting the copy on write dupplicated tile.");
+    }
+
   return new_buffer;
 }
 



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