[gegl] Make COW work for gegl_buffer_copy



commit 2b213ccc163b0580791fd002971709313898d6f1
Author: Ãyvind KolÃs <pippin gimp org>
Date:   Mon Apr 9 17:49:07 2012 +0200

    Make COW work for gegl_buffer_copy
    
    Not entirely sure if it works, disabling it as well as using non COW but
    similar code paths is easy.

 gegl/buffer/gegl-buffer-access.c      |  191 +++++++++++++++++++++++++++++++++
 gegl/buffer/gegl-buffer-iterator.c    |   12 +-
 gegl/buffer/gegl-buffer-private.h     |    8 ++
 gegl/buffer/gegl-tile-handler-cache.c |    7 +-
 gegl/buffer/gegl-tile.c               |    2 +-
 5 files changed, 212 insertions(+), 8 deletions(-)
---
diff --git a/gegl/buffer/gegl-buffer-access.c b/gegl/buffer/gegl-buffer-access.c
index 1fe700b..13be852 100644
--- a/gegl/buffer/gegl-buffer-access.c
+++ b/gegl/buffer/gegl-buffer-access.c
@@ -1136,6 +1136,48 @@ 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));
+
+  if (!src_rect)
+    {
+      src_rect = gegl_buffer_get_extent (src);
+    }
+
+  if (!dst_rect)
+    {
+      dst_rect = src_rect;
+    }
+
+  if (src_rect->width == 0 || src_rect->height == 0)
+    return;
+
+  fish = babl_fish (src->soft_format, dst->soft_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, 0, dst->soft_format, 
+                                    GEGL_BUFFER_WRITE, GEGL_ABYSS_NONE);
+      read = gegl_buffer_iterator_add (i, src, src_rect, 0, src->soft_format,
+                                       GEGL_BUFFER_READ, GEGL_ABYSS_NONE);
+      while (gegl_buffer_iterator_next (i) && i->length > 0)
+        babl_process (fish, i->data[read], i->data[0], i->length);
+    }
+}
+
 void
 gegl_buffer_copy (GeglBuffer          *src,
                   const GeglRectangle *src_rect,
@@ -1156,6 +1198,155 @@ gegl_buffer_copy (GeglBuffer          *src,
       dst_rect = src_rect;
     }
 
+
+  if (src->soft_format == dst->soft_format &&
+      gegl_buffer_scan_compatible (src, src_rect->x, src_rect->y,
+                                   dst, dst_rect->x, dst_rect->y))
+    {
+      GeglRectangle dest_rect_r = *dst_rect;
+
+      gint tile_width = src->tile_width;
+      gint tile_height = src->tile_height;
+      tile_width = dst->tile_width;
+      tile_height = dst->tile_height;
+
+      dest_rect_r.width = src_rect->width;
+      dest_rect_r.height = src_rect->height;
+      dst_rect = &dest_rect_r;
+
+      {
+        GeglRectangle cow_rect = *dst_rect;
+
+        /* adjust origin until we match the start of tile alignment */
+        while ( (cow_rect.x + dst->shift_x) % tile_width)
+          {
+            cow_rect.x ++;
+            cow_rect.width --;
+          }
+        while ( (cow_rect.y + dst->shift_y) % tile_height)
+          {
+            cow_rect.y ++;
+            cow_rect.height --;
+          }
+        /* adjust size of rect to match multiple of tiles */
+
+        cow_rect.width  = cow_rect.width  - (cow_rect.width  % tile_width);
+        cow_rect.height = cow_rect.height - (cow_rect.height % tile_height);
+        {
+          GeglRectangle top, bottom, left, right;
+          
+          /* iterate over rectangle that can be cow copied, duplicating
+           * one and one tile
+           */
+          {
+            /* first we do a dumb copy,. but with fetched tiles */
+
+            gint dst_x, dst_y;
+            GeglTileHandlerChain   *storage;
+            GeglTileHandlerCache   *cache;
+ 
+            storage = GEGL_TILE_HANDLER_CHAIN (dst->tile_storage);
+            cache = GEGL_TILE_HANDLER_CACHE (gegl_tile_handler_chain_get_first (storage, GEGL_TYPE_TILE_HANDLER_CACHE));
+
+            for (dst_y = cow_rect.y + dst->shift_y; dst_y < cow_rect.y + dst->shift_y + cow_rect.height; dst_y += tile_height)
+            for (dst_x = cow_rect.x + dst->shift_x; dst_x < cow_rect.x + dst->shift_x + cow_rect.width; dst_x += tile_width)
+              {
+                GeglTile *src_tile;
+                GeglTile *dst_tile;
+                gint src_x, src_y;
+                gint stx, sty, dtx, dty;
+
+                src_x = dst_x - (dst_rect->x - src_rect->x) + src->shift_x;
+                src_y = dst_y - (dst_rect->y - src_rect->y) + src->shift_y;
+
+                stx = gegl_tile_indice (src_x, tile_width);
+                sty = gegl_tile_indice (src_y, tile_height);
+                dtx = gegl_tile_indice (dst_x, tile_width);
+                dty = gegl_tile_indice (dst_y, tile_height);
+
+#if 1
+                src_tile = gegl_tile_source_get_tile ((GeglTileSource*)(src),
+                                                      stx, sty, 0);
+
+                dst_tile = gegl_tile_dup (src_tile);
+                dst_tile->tile_storage = (void*)storage;
+
+                /* XXX: this call should only be neccesary as long as GIMP
+                 *      is dropping tile caches behind our back
+                 */
+                if(gegl_tile_source_set_tile ((GeglTileSource*)dst, dtx, dty, 0, 
+                                           dst_tile));
+                gegl_tile_handler_cache_insert (cache, dst_tile, dtx, dty, 0);
+
+                gegl_tile_unref (src_tile);
+                gegl_tile_unref (dst_tile);
+#else
+                src_tile = gegl_tile_source_get_tile (
+                  (GeglTileSource*)(src), stx, sty, 0);
+                dst_tile = gegl_tile_source_get_tile (
+                  (GeglTileSource*)(dst), dtx, dty, 0);
+                gegl_tile_lock (dst_tile);
+                g_assert (src_tile->size == dst_tile->size);
+
+                memcpy (dst_tile->data, src_tile->data, src_tile->size);
+
+                gegl_tile_unlock (dst_tile);
+                gegl_tile_unref (dst_tile);
+                gegl_tile_unref (src_tile);
+#endif
+              }
+          }
+
+          top = *dst_rect;
+          top.height = (cow_rect.y - dst_rect->y);
+
+
+          left = *dst_rect;
+          left.y = cow_rect.y;
+          left.height = cow_rect.height;
+          left.width = (cow_rect.x - dst_rect->x);
+
+          bottom = *dst_rect;
+          bottom.y = (cow_rect.y + cow_rect.height);
+          bottom.height = (dst_rect->y + dst_rect->height) -
+                          (cow_rect.y  + cow_rect.height);
+
+          right  =  *dst_rect;
+          right.x = (cow_rect.x + cow_rect.width);
+          right.width = (dst_rect->x + dst_rect->width) -
+                          (cow_rect.x  + cow_rect.width);
+          right.y = cow_rect.y;
+          right.height = cow_rect.height;
+
+          if (top.height)
+          gegl_buffer_copy2 (src, 
+                             GEGL_RECTANGLE (src_rect->x + (top.x-dst_rect->x),
+                                             src_rect->y + (top.y-dst_rect->y),
+                                 top.width, top.height),
+                             dst, &top);
+          if (bottom.height)
+          gegl_buffer_copy2 (src, 
+                             GEGL_RECTANGLE (src_rect->x + (bottom.x-dst_rect->x),
+                                             src_rect->y + (bottom.y-dst_rect->y),
+                                 bottom.width, bottom.height),
+                             dst, &bottom);
+          if (left.width)
+          gegl_buffer_copy2 (src, 
+                             GEGL_RECTANGLE (src_rect->x + (left.x-dst_rect->x),
+                                             src_rect->y + (left.y-dst_rect->y),
+                                 left.width, left.height),
+                             dst, &left);
+          if (right.width && right.height)
+          gegl_buffer_copy2 (src, 
+                             GEGL_RECTANGLE (src_rect->x + (right.x-dst_rect->x),
+                                             src_rect->y + (right.y-dst_rect->y),
+                                 right.width, right.height),
+                             dst, &right);
+        }
+      }
+      return;
+    }
+
   fish = babl_fish (src->soft_format, dst->soft_format);
 
     {
diff --git a/gegl/buffer/gegl-buffer-iterator.c b/gegl/buffer/gegl-buffer-iterator.c
index 5a08a7e..6c2e0c8 100644
--- a/gegl/buffer/gegl-buffer-iterator.c
+++ b/gegl/buffer/gegl-buffer-iterator.c
@@ -96,12 +96,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)
diff --git a/gegl/buffer/gegl-buffer-private.h b/gegl/buffer/gegl-buffer-private.h
index 9e2e449..bc6f792 100644
--- a/gegl/buffer/gegl-buffer-private.h
+++ b/gegl/buffer/gegl-buffer-private.h
@@ -176,6 +176,14 @@ struct _GeglTile
 
 void _gegl_buffer_drop_hot_tile (GeglBuffer *buffer);
 
+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))
 #endif // __GEGL_TILE_C
diff --git a/gegl/buffer/gegl-tile-handler-cache.c b/gegl/buffer/gegl-tile-handler-cache.c
index 79ad119..a0bc2f6 100644
--- a/gegl/buffer/gegl-tile-handler-cache.c
+++ b/gegl/buffer/gegl-tile-handler-cache.c
@@ -213,7 +213,7 @@ gegl_tile_handler_cache_dispose (GObject *object)
       g_static_mutex_unlock (&mutex);
     }
 
-  if (cache->count != 0)
+  if (cache->count < 0)
     {
       g_warning ("cache-handler tile balance not zero: %i\n", cache->count);
     }
@@ -495,6 +495,7 @@ gegl_tile_handler_cache_void (GeglTileHandlerCache *cache,
           g_slice_free (CacheItem, item);
           g_queue_delete_link (cache_queue, link);
           g_static_mutex_unlock (&mutex);
+          cache->count --;
           return;
         }
     }
@@ -516,12 +517,16 @@ gegl_tile_handler_cache_insert (GeglTileHandlerCache *cache,
   item->y       = y;
   item->z       = z;
 
+  // XXX : remove entry if it already exists
+  gegl_tile_handler_cache_void (cache, x, y, z);
+
   g_static_mutex_lock (&mutex);
   cache_total  += item->tile->size;
   g_queue_push_head (cache_queue, item);
 
   cache->count ++;
 
+
   g_hash_table_insert (cache_ht, item, item);
 
   while (cache_total > gegl_config()->cache_size)
diff --git a/gegl/buffer/gegl-tile.c b/gegl/buffer/gegl-tile.c
index d89d893..e80434a 100644
--- a/gegl/buffer/gegl-tile.c
+++ b/gegl/buffer/gegl-tile.c
@@ -298,7 +298,7 @@ gegl_tile_is_stored (GeglTile *tile)
 void
 gegl_tile_void (GeglTile *tile)
 {
-  tile->stored_rev = tile->rev;
+  gegl_tile_mark_as_stored (tile);
   tile->tile_storage = NULL;
   if (tile->z==0)
     gegl_tile_void_pyramid (tile);



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