[gegl] buffer: do COW for tiles during gegl_buffer_dup



commit 72e784cbc8fd474123f85786b6d4895957a773d0
Author: Ãyvind KolÃs <pippin gimp org>
Date:   Thu Mar 22 21:17:00 2012 +0000

    buffer: do COW for tiles during gegl_buffer_dup

 gegl/buffer/gegl-buffer-access.c   |   85 ++++++++++++++++++++++++++++++------
 gegl/buffer/gegl-buffer-iterator.c |   18 +++----
 gegl/buffer/gegl-buffer-private.h  |    6 +++
 3 files changed, 86 insertions(+), 23 deletions(-)
---
diff --git a/gegl/buffer/gegl-buffer-access.c b/gegl/buffer/gegl-buffer-access.c
index fd5aae6..1f7b379 100644
--- a/gegl/buffer/gegl-buffer-access.c
+++ b/gegl/buffer/gegl-buffer-access.c
@@ -1139,6 +1139,36 @@ gegl_buffer_sample_cleanup (GeglBuffer *buffer)
     }
 }
 
+static void
+gegl_buffer_copy2 (GeglBuffer          *src,
+                   const GeglRectangle *src_rect,
+                   GeglBuffer          *dst,
+                   const GeglRectangle *dst_rect)
+{
+  const Babl *fish;
+
+  g_return_if_fail (GEGL_IS_BUFFER (src));
+  g_return_if_fail (GEGL_IS_BUFFER (dst));
+  g_return_if_fail (src_rect);
+  g_return_if_fail (dst_rect);
+
+  fish = babl_fish (src->format, dst->format);
+
+  {
+    GeglRectangle dest_rect_r = *dst_rect;
+    GeglBufferIterator *i;
+    gint read;
+
+    dest_rect_r.width = src_rect->width;
+    dest_rect_r.height = src_rect->height;
+
+    i = gegl_buffer_iterator_new (dst, &dest_rect_r, dst->format, GEGL_BUFFER_WRITE);
+    read = gegl_buffer_iterator_add (i, src, src_rect, src->format, GEGL_BUFFER_READ);
+    while (gegl_buffer_iterator_next (i))
+      babl_process (fish, i->data[read], i->data[0], i->length);
+  }
+}
+
 void
 gegl_buffer_copy (GeglBuffer          *src,
                   const GeglRectangle *src_rect,
@@ -1160,21 +1190,50 @@ gegl_buffer_copy (GeglBuffer          *src,
       dst_rect = src_rect;
     }
 
-  fish = babl_fish (src->format, dst->format);
-
+  /* for now, only doing the zero copy when we effectively are doing a buffer
+   * dup.
+   */
+  if (src->format == dst->format &&
+      _gegl_buffer_scan_compatible (src,
+                                    src_rect->x,
+                                    src_rect->y,
+                                    dst,
+                                    dst_rect->x,
+                                    dst_rect->y) &&
+      !memcmp (src_rect, dst_rect, sizeof (GeglRectangle)) &&
+      src_rect->x == 0 &&
+      src_rect->y == 0)
     {
-      GeglRectangle dest_rect_r = *dst_rect;
-      GeglBufferIterator *i;
-      gint read;
-
-      dest_rect_r.width = src_rect->width;
-      dest_rect_r.height = src_rect->height;
-
-      i = gegl_buffer_iterator_new (dst, &dest_rect_r, dst->format, GEGL_BUFFER_WRITE);
-      read = gegl_buffer_iterator_add (i, src, src_rect, src->format, GEGL_BUFFER_READ);
-      while (gegl_buffer_iterator_next (i))
-        babl_process (fish, i->data[read], i->data[0], i->length);
+      int i;
+      int x, y;
+      int tile_width = dst->tile_storage->tile_width;
+      int tile_height = dst->tile_storage->tile_height;
+      /* determine inner region that can definetly be shared */
+
+      /* share this inner region */
+      for (y = dst_rect->y; y < dst_rect->y + dst_rect->height; y += tile_height)
+      for (x = dst_rect->x; x < dst_rect->x + dst_rect->width;  x += tile_width)
+        {
+          GeglTile *src_tile;
+          GeglTile *dst_tile;
+          int res;
+          src_tile = gegl_tile_source_get_tile ((GeglTileSource *)(src),
+                                                gegl_tile_indice (x, tile_width),
+                                                gegl_tile_indice (y, tile_height),
+                                                0);
+          dst_tile = gegl_tile_dup (src_tile);
+          res = gegl_tile_source_set_tile ((GeglTileSource*)(dst),
+                                           gegl_tile_indice (x, tile_width),
+                                           gegl_tile_indice (y, tile_height),
+                                           0,
+                                           dst_tile);
+          if (res) res = 0;
+          gegl_tile_unref (src_tile);
+        }
+      /* copy up to four regions around : NYI */
+      return;
     }
+  gegl_buffer_copy2 (src, src_rect, dst, dst_rect);
 }
 
 void
diff --git a/gegl/buffer/gegl-buffer-iterator.c b/gegl/buffer/gegl-buffer-iterator.c
index 523b918..ec009f8 100644
--- a/gegl/buffer/gegl-buffer-iterator.c
+++ b/gegl/buffer/gegl-buffer-iterator.c
@@ -93,12 +93,12 @@ 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.
  */
-static gboolean gegl_buffer_scan_compatible (GeglBuffer *bufferA,
-                                             gint        xA,
-                                             gint        yA,
-                                             GeglBuffer *bufferB,
-                                             gint        xB,
-                                             gint        yB)
+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)
@@ -244,8 +244,6 @@ static glong in_direct_read = 0;
 static glong in_direct_write = 0;
 #endif
 
-
-
 gint
 gegl_buffer_iterator_add (GeglBufferIterator  *iterator,
                           GeglBuffer          *buffer,
@@ -290,8 +288,8 @@ gegl_buffer_iterator_add (GeglBufferIterator  *iterator,
       i->rect[self].width = i->rect[0].width;
       i->rect[self].height = i->rect[0].height;
 
-      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))
+      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));
diff --git a/gegl/buffer/gegl-buffer-private.h b/gegl/buffer/gegl-buffer-private.h
index 9cf188f..0780c13 100644
--- a/gegl/buffer/gegl-buffer-private.h
+++ b/gegl/buffer/gegl-buffer-private.h
@@ -174,6 +174,12 @@ struct _GeglTile
   gpointer         unlock_notify_data;
 };
 
+gboolean _gegl_buffer_scan_compatible (GeglBuffer *bufferA,
+                                       gint        xA,
+                                       gint        yA,
+                                       GeglBuffer *bufferB,
+                                       gint        xB,
+                                       gint        yB);
 
 #ifndef __GEGL_TILE_C
 #define gegl_tile_get_data(tile)  ((guchar*)((tile)->data))



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