[gegl] buffer: keep track of damage-region of mipmapped tiles



commit 3210f4ffc3c569a2acd9483811cb141070112bc6
Author: Ell <ell_se yahoo com>
Date:   Sat Mar 31 11:45:55 2018 -0400

    buffer: keep track of damage-region of mipmapped tiles
    
    WIP

 gegl/buffer/gegl-buffer-access.c      |    6 +-
 gegl/buffer/gegl-buffer-iterator.c    |   13 ++-
 gegl/buffer/gegl-buffer-private.h     |    6 +
 gegl/buffer/gegl-tile-handler-cache.c |   39 ++++---
 gegl/buffer/gegl-tile-handler-zoom.c  |  184 +++++++++++++++++++++++---------
 gegl/buffer/gegl-tile-handler.c       |   52 +++++++++-
 gegl/buffer/gegl-tile.c               |   88 ++++++++++++++--
 7 files changed, 305 insertions(+), 83 deletions(-)
---
diff --git a/gegl/buffer/gegl-buffer-access.c b/gegl/buffer/gegl-buffer-access.c
index bb2d0eb..34e4435 100644
--- a/gegl/buffer/gegl-buffer-access.c
+++ b/gegl/buffer/gegl-buffer-access.c
@@ -826,12 +826,16 @@ with multi-threading - and should be added back later.
               #undef CHECK_ALIGNMENT_ALIGNOF
             }
 
-          gegl_tile_unlock (tile);
+          gegl_tile_unlock_no_void (tile);
           gegl_tile_unref (tile);
           bufx += (tile_width - offsetx);
         }
       bufy += (tile_height - offsety);
     }
+
+  if (level == 0)
+    gegl_tile_handler_damage_rect (GEGL_TILE_HANDLER (buffer->tile_storage),
+                                   roi);
 }
 
 static inline void
diff --git a/gegl/buffer/gegl-buffer-iterator.c b/gegl/buffer/gegl-buffer-iterator.c
index 7411726..9c1ea22 100644
--- a/gegl/buffer/gegl-buffer-iterator.c
+++ b/gegl/buffer/gegl-buffer-iterator.c
@@ -193,7 +193,7 @@ release_tile (GeglBufferIterator *iter,
   if (sub->current_tile_mode == GeglIteratorTileMode_DirectTile)
     {
       if (sub->access_mode & GEGL_ACCESS_WRITE)
-        gegl_tile_unlock (sub->current_tile);
+        gegl_tile_unlock_no_void (sub->current_tile);
       gegl_tile_unref (sub->current_tile);
 
       sub->current_tile = NULL;
@@ -545,10 +545,19 @@ _gegl_buffer_iterator_stop (GeglBufferIterator *iter)
           if (sub->linear_tile)
             {
               if (sub->access_mode & GEGL_ACCESS_WRITE)
-                gegl_tile_unlock (sub->linear_tile);
+                gegl_tile_unlock_no_void (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))
+            {
+              gegl_tile_handler_damage_rect (
+                GEGL_TILE_HANDLER (sub->buffer->tile_storage),
+                &sub->full_rect);
+            }
+
           gegl_buffer_unlock (sub->buffer);
 
           if ((sub->access_mode & GEGL_ACCESS_WRITE) &&
diff --git a/gegl/buffer/gegl-buffer-private.h b/gegl/buffer/gegl-buffer-private.h
index 9df62bf..d7e700d 100644
--- a/gegl/buffer/gegl-buffer-private.h
+++ b/gegl/buffer/gegl-buffer-private.h
@@ -176,6 +176,8 @@ struct _GeglTile
                                  * are in the cache.
                                  */
 
+  guint64          damage;
+
   /* called when the tile is about to be destroyed */
   GDestroyNotify   destroy_notify;
   gpointer         destroy_notify_data;
@@ -187,6 +189,10 @@ struct _GeglTile
   gpointer         unlock_notify_data;
 };
 
+void     gegl_tile_unlock_no_void (GeglTile *tile);
+gboolean gegl_tile_damage         (GeglTile *tile,
+                                   guint64   damage);
+
 void _gegl_buffer_drop_hot_tile (GeglBuffer *buffer);
 
 GeglRectangle _gegl_get_required_for_scale (const GeglRectangle *roi,
diff --git a/gegl/buffer/gegl-tile-handler-cache.c b/gegl/buffer/gegl-tile-handler-cache.c
index 0688153..6914fe1 100644
--- a/gegl/buffer/gegl-tile-handler-cache.c
+++ b/gegl/buffer/gegl-tile-handler-cache.c
@@ -78,7 +78,8 @@ void              gegl_tile_handler_cache_insert     (GeglTileHandlerCache *cach
 static void       gegl_tile_handler_cache_void       (GeglTileHandlerCache *cache,
                                                       gint                  x,
                                                       gint                  y,
-                                                      gint                  z);
+                                                      gint                  z,
+                                                      guint64               damage);
 static void       gegl_tile_handler_cache_invalidate (GeglTileHandlerCache *cache,
                                                       gint                  x,
                                                       gint                  y,
@@ -284,7 +285,9 @@ gegl_tile_handler_cache_command (GeglTileSource  *tile_store,
         gegl_tile_handler_cache_invalidate (cache, x, y, z);
         break;
       case GEGL_TILE_VOID:
-        gegl_tile_handler_cache_void (cache, x, y, z);
+        gegl_tile_handler_cache_void (cache, x, y, z,
+                                      data ? *(const guint64 *) data :
+                                             ~(guint64) 0);
         break;
       case GEGL_TILE_REINIT:
         gegl_tile_handler_cache_reinit (cache);
@@ -651,29 +654,33 @@ static void
 gegl_tile_handler_cache_void (GeglTileHandlerCache *cache,
                               gint                  x,
                               gint                  y,
-                              gint                  z)
+                              gint                  z,
+                              guint64               damage)
 {
   CacheItem *item;
 
   item = cache_lookup (cache, x, y, z);
   if (item)
     {
-      if (g_atomic_int_dec_and_test (gegl_tile_n_cached_clones (item->tile)))
-        g_atomic_pointer_add (&cache_total, -item->tile->size);
-      g_atomic_pointer_add (&cache_total_uncloned, -item->tile->size);
+      drop_hot_tile (item->tile);
 
-      g_queue_unlink (&cache->queue, &item->link);
-      g_hash_table_remove (cache->items, item);
+      if (gegl_tile_damage (item->tile, damage))
+        {
+          if (g_atomic_int_dec_and_test (gegl_tile_n_cached_clones (item->tile)))
+            g_atomic_pointer_add (&cache_total, -item->tile->size);
+          g_atomic_pointer_add (&cache_total_uncloned, -item->tile->size);
 
-      if (g_queue_is_empty (&cache->queue))
-        cache->time = cache->stamp = 0;
+          g_queue_unlink (&cache->queue, &item->link);
+          g_hash_table_remove (cache->items, item);
 
-      drop_hot_tile (item->tile);
-      gegl_tile_void (item->tile);
-      item->tile->tile_storage = NULL;
-      gegl_tile_unref (item->tile);
+          if (g_queue_is_empty (&cache->queue))
+            cache->time = cache->stamp = 0;
 
-      g_slice_free (CacheItem, item);
+          item->tile->tile_storage = NULL;
+          gegl_tile_unref (item->tile);
+
+          g_slice_free (CacheItem, item);
+        }
     }
 }
 
@@ -695,7 +702,7 @@ gegl_tile_handler_cache_insert (GeglTileHandlerCache *cache,
   item->z         = z;
 
   // XXX : remove entry if it already exists
-  gegl_tile_handler_cache_void (cache, x, y, z);
+  gegl_tile_handler_cache_void (cache, x, y, z, ~(guint64) 0);
 
   tile->x = x;
   tile->y = y;
diff --git a/gegl/buffer/gegl-tile-handler-zoom.c b/gegl/buffer/gegl-tile-handler-zoom.c
index a8037de..79fd563 100644
--- a/gegl/buffer/gegl-tile-handler-zoom.c
+++ b/gegl/buffer/gegl-tile-handler-zoom.c
@@ -29,6 +29,7 @@
 #include "gegl-tile-handler-private.h"
 #include "gegl-tile-handler-zoom.h"
 #include "gegl-tile-storage.h"
+#include "gegl-buffer-private.h"
 #include "gegl-algorithms.h"
 
 
@@ -37,52 +38,101 @@ G_DEFINE_TYPE (GeglTileHandlerZoom, gegl_tile_handler_zoom,
 
 static guint64 total_size = 0;
 
-static inline void set_blank (GeglTile   *dst_tile,
-                              gint        width,
-                              gint        height,
-                              const Babl *format,
-                              gint        i,
-                              gint        j)
+static void
+downscale (GeglTileHandlerZoom *zoom,
+           const Babl          *format,
+           gint                 bpp,
+           guchar              *src,
+           guchar              *dest,
+           gint                 stride,
+           gint                 x,
+           gint                 y,
+           gint                 width,
+           gint                 height,
+           guint                damage,
+           gint                 i)
 {
-  guchar *dst_data  = gegl_tile_get_data (dst_tile);
-  gint    bpp       = babl_format_get_bytes_per_pixel (format);
-  gint    rowstride = width * bpp;
-  gint    scanline;
-
-  gint    bytes = width * bpp / 2;
-  guchar *dst   = dst_data + j * height / 2 * rowstride + i * rowstride / 2;
+  gint  n    = 1 << i;
+  guint mask = (1 << n) - 1;
 
-  for (scanline = 0; scanline < height / 2; scanline++)
+  if ((damage & mask) == mask)
     {
-      memset (dst, 0x0, bytes);
-      dst += rowstride;
-    }
+      if (src)
+        {
+          if (!zoom->downscale_2x2)
+            zoom->downscale_2x2 = gegl_downscale_2x2_get_fun (format);
 
-  total_size += (height / 2) * bytes;
-}
+          zoom->downscale_2x2 (format,
+                               width, height,
+                               src +   y      * stride +  x      * bpp, stride,
+                               dest + (y / 2) * stride + (x / 2) * bpp, stride);
+        }
+      else
+        {
+          gint h = height / 2;
+          gint n = (width / 2) * bpp;
+          gint i;
 
-static inline void set_half (GeglTileHandlerZoom *zoom,
-                             GeglTile   * dst_tile,
-                             GeglTile   * src_tile,
-                             gint         width,
-                             gint         height,
-                             const Babl * format,
-                             gint i,
-                             gint j)
-{
-  guchar     *dst_data   = gegl_tile_get_data (dst_tile);
-  guchar     *src_data   = gegl_tile_get_data (src_tile);
-  gint        bpp        = babl_format_get_bytes_per_pixel (format);
+          dest += (y / 2) * stride + (x / 2) * bpp;
 
-  if (i) dst_data += bpp * width / 2;
-  if (j) dst_data += bpp * width * height / 2;
+          for (i = 0; i < h; i++)
+            {
+              memset (dest, 0, n);
+              dest += stride;
+            }
+        }
+
+      total_size += (width / 2) * (height / 2) * bpp;
+    }
+  else
+    {
+      i--;
+      n    /=  2;
+      mask >>= n;
+
+      if (damage & mask)
+        {
+          if (i & 1)
+            {
+              downscale (zoom,
+                         format, bpp, src, dest, stride,
+                         x, y,
+                         width, height / 2,
+                         damage, i);
+            }
+          else
+            {
+              downscale (zoom,
+                         format, bpp, src, dest, stride,
+                         x, y,
+                         width / 2, height,
+                         damage, i);
 
-  if (!zoom->downscale_2x2)
-    zoom->downscale_2x2 = gegl_downscale_2x2_get_fun (format);
+            }
+        }
 
-  zoom->downscale_2x2 (format, width, height, src_data, width * bpp, dst_data, width * bpp);
+      damage >>= n;
 
-  total_size += (width / 2) * (height / 2) * bpp;
+      if (damage & mask)
+        {
+          if (i & 1)
+            {
+              downscale (zoom,
+                         format, bpp, src, dest, stride,
+                         x, y + height / 2,
+                         width, height / 2,
+                         damage, i);
+            }
+          else
+            {
+              downscale (zoom,
+                         format, bpp, src, dest, stride,
+                         x + width / 2, y,
+                         width / 2, height,
+                         damage, i);
+            }
+        }
+    }
 }
 
 static GeglTile *
@@ -101,7 +151,7 @@ get_tile (GeglTileSource *gegl_tile_source,
   if (source)
     tile = gegl_tile_source_get_tile (source, x, y, z);
 
-  if (tile || (z == 0))
+  if (z == 0 || (tile && ! tile->damage))
     return tile;
 
   tile_storage = _gegl_tile_handler_get_tile_storage ((GeglTileHandler *) zoom);
@@ -114,16 +164,27 @@ get_tile (GeglTileSource *gegl_tile_source,
 
   {
     gint        i, j;
-    const Babl *format = gegl_tile_backend_get_format (zoom->backend);
+    const Babl *format;
+    gint        bpp;
+    gint        stride;
+    guint64     damage;
     GeglTile   *source_tile[2][2] = { { NULL, NULL }, { NULL, NULL } };
 
+    if (tile)
+      damage = tile->damage;
+    else
+      damage = ~(guint64) 0;
+
     for (i = 0; i < 2; i++)
       for (j = 0; j < 2; j++)
         {
-          /* we get the tile from ourselves, to make successive rescales work
-           * correctly */
-            source_tile[i][j] = gegl_tile_source_get_tile (gegl_tile_source,
-                                                          x * 2 + i, y * 2 + j, z - 1);
+          if ((damage >> (32 * j + 16 * i)) & 0xffff)
+            {
+              /* we get the tile from ourselves, to make successive rescales
+               * work correctly */
+              source_tile[i][j] = gegl_tile_source_get_tile (
+                gegl_tile_source, x * 2 + i, y * 2 + j, z - 1);
+            }
         }
 
     if (source_tile[0][0] == NULL &&
@@ -135,23 +196,42 @@ get_tile (GeglTileSource *gegl_tile_source,
                           fill in the shared empty tile */
       }
 
-    g_assert (tile == NULL);
+    format = gegl_tile_backend_get_format (zoom->backend);
+    bpp    = babl_format_get_bytes_per_pixel (format);
+    stride = tile_width * bpp;
 
-    tile = gegl_tile_handler_create_tile (GEGL_TILE_HANDLER (zoom), x, y, z);
+    if (! tile)
+      tile = gegl_tile_handler_create_tile (GEGL_TILE_HANDLER (zoom), x, y, z);
 
     gegl_tile_lock (tile);
 
     for (i = 0; i < 2; i++)
       for (j = 0; j < 2; j++)
         {
-          if (source_tile[i][j])
-            {
-              set_half (zoom, tile, source_tile[i][j], tile_width, tile_height, format, i, j);
-              gegl_tile_unref (source_tile[i][j]);
-            }
-          else
+          guint dmg = (damage >> (32 * j + 16 * i)) & 0xffff;
+
+          if (dmg)
             {
-              set_blank (tile, tile_width, tile_height, format, i, j);
+              gint x = i * tile_width / 2;
+              gint y = j * tile_height / 2;
+              guchar *src;
+              guchar *dest;
+
+              if (source_tile[i][j] && ! source_tile[i][j]->is_zero_tile)
+                src = gegl_tile_get_data (source_tile[i][j]);
+              else
+                src = NULL;
+
+              dest = gegl_tile_get_data (tile) + y * stride + x * bpp;
+
+              downscale (zoom,
+                         format, bpp, src, dest, stride,
+                         0, 0,
+                         tile_width, tile_height,
+                         dmg, 4);
+
+              if (source_tile[i][j])
+                gegl_tile_unref (source_tile[i][j]);
             }
         }
     gegl_tile_unlock (tile);
diff --git a/gegl/buffer/gegl-tile-handler.c b/gegl/buffer/gegl-tile-handler.c
index 53a9cda..9d9f54e 100644
--- a/gegl/buffer/gegl-tile-handler.c
+++ b/gegl/buffer/gegl-tile-handler.c
@@ -269,6 +269,8 @@ gegl_tile_handler_damage_rect (GeglTileHandler     *handler,
 
   for (z = 1; z <= handler->priv->tile_storage->seen_zoom; z++)
     {
+      gint U1, V1;
+      gint U2, V2;
       gint x,  y;
 
       X1 >>= 1;
@@ -281,11 +283,59 @@ gegl_tile_handler_damage_rect (GeglTileHandler     *handler,
       x2 >>= 1;
       y2 >>= 1;
 
+      U1 = 8 * (X1 - x1 * tile_width)  / tile_width;
+      V1 = 8 * (Y1 - y1 * tile_height) / tile_height;
+      U2 = 8 * (X2 - x2 * tile_width)  / tile_width;
+      V2 = 8 * (Y2 - y2 * tile_height) / tile_height;
+
       for (x = x1; x <= x2; x++)
         {
+          gint  u1 = x == x1 ? U1 : 0;
+          gint  u2 = x == x2 ? U2 : 7;
+          guint base;
+
+          if (u1 == 0 && u2 == 7)
+            {
+              base = 0x00330033;
+            }
+          else
+            {
+              gint i;
+
+              base = 0;
+
+              for (i = u1; i <= u2; i++)
+                {
+                  base |= 1 << (((i & 1) << 0) |
+                                ((i & 2) << 1) |
+                                ((i & 4) << 2));
+                }
+            }
+
           for (y = y1; y <= y2; y++)
             {
-              gegl_tile_source_void (source, x, y, z);
+              gint v1 = y == y1 ? V1 : 0;
+              gint v2 = y == y2 ? V2 : 7;
+
+              if (u1 + v1 == 0 && u2 + v2 == 14)
+                {
+                  gegl_tile_source_void (source, x, y, z);
+                }
+              else
+                {
+                  guint64 damage = 0;
+                  gint    i;
+
+                  for (i = v1; i <= v2; i++)
+                    {
+                      damage |= (guint64) base << (((i & 1) << 1) |
+                                                   ((i & 2) << 2) |
+                                                   ((i & 4) << 3));
+                    }
+
+                  gegl_tile_source_command (source, GEGL_TILE_VOID, x, y, z,
+                                            &damage);
+                }
             }
         }
     }
diff --git a/gegl/buffer/gegl-tile.c b/gegl/buffer/gegl-tile.c
index 3392b49..eef551f 100644
--- a/gegl/buffer/gegl-tile.c
+++ b/gegl/buffer/gegl-tile.c
@@ -131,6 +131,7 @@ gegl_tile_dup (GeglTile *src)
   GeglTile *tile = gegl_tile_new_bare_internal ();
 
   g_warn_if_fail (src->lock_count == 0);
+  g_warn_if_fail (! src->damage);
 
   src->clone_state   = CLONE_STATE_CLONED;
 
@@ -282,16 +283,43 @@ static inline void
 _gegl_tile_void_pyramid (GeglTileSource *source,
                          gint            x,
                          gint            y,
-                         gint            z)
+                         gint            z,
+                         guint64         damage)
 {
-  if (z > ((GeglTileStorage*)source)->seen_zoom)
+  guint new_damage;
+  guint mask;
+  gint  i;
+
+  if (z >= ((GeglTileStorage*)source)->seen_zoom)
     return;
-  gegl_tile_source_void (source, x, y, z);
-  _gegl_tile_void_pyramid (source, x/2, y/2, z+1);
+
+  damage |= damage >> 1;
+  damage |= damage >> 2;
+
+  new_damage = 0;
+  mask       = 1;
+
+  for (i = 0; i < 16; i++)
+    {
+      new_damage |= damage & mask;
+      damage >>= 3;
+      mask   <<= 1;
+    }
+
+  damage = (guint64) new_damage << (32 * (y & 1) + 16 * (x & 1));
+
+  x >>= 1;
+  y >>= 1;
+  z++;
+
+  gegl_tile_source_command (source, GEGL_TILE_VOID, x, y, z, &damage);
+
+  _gegl_tile_void_pyramid (source, x, y, z, damage);
 }
 
 static inline void
-gegl_tile_void_pyramid (GeglTile *tile)
+gegl_tile_void_pyramid (GeglTile *tile,
+                        guint64   damage)
 {
   if (tile->tile_storage &&
       tile->tile_storage->seen_zoom &&
@@ -301,9 +329,10 @@ gegl_tile_void_pyramid (GeglTile *tile)
         g_rec_mutex_lock (&tile->tile_storage->mutex);
 
       _gegl_tile_void_pyramid (GEGL_TILE_SOURCE (tile->tile_storage),
-                               tile->x/2,
-                               tile->y/2,
-                               tile->z+1);
+                               tile->x,
+                               tile->y,
+                               tile->z,
+                               damage);
 
       if (gegl_config_threads()>1)
         g_rec_mutex_unlock (&tile->tile_storage->mutex);
@@ -318,6 +347,7 @@ gegl_tile_unlock (GeglTile *tile)
   if (g_atomic_int_dec_and_test (&tile->lock_count))
     {
       g_atomic_int_inc (&tile->rev);
+      tile->damage = 0;
 
       if (tile->unlock_notify != NULL)
         {
@@ -326,7 +356,22 @@ gegl_tile_unlock (GeglTile *tile)
 
       if (tile->z == 0)
         {
-          gegl_tile_void_pyramid (tile);
+          gegl_tile_void_pyramid (tile, ~(guint64) 0);
+        }
+    }
+}
+
+void
+gegl_tile_unlock_no_void (GeglTile *tile)
+{
+  if (g_atomic_int_dec_and_test (&tile->lock_count))
+    {
+      g_atomic_int_inc (&tile->rev);
+      tile->damage = 0;
+
+      if (tile->unlock_notify != NULL)
+        {
+          tile->unlock_notify (tile, tile->unlock_notify_data);
         }
     }
 }
@@ -349,7 +394,28 @@ gegl_tile_void (GeglTile *tile)
   gegl_tile_mark_as_stored (tile);
 
   if (tile->z == 0)
-    gegl_tile_void_pyramid (tile);
+    gegl_tile_void_pyramid (tile, ~(guint64) 0);
+}
+
+gboolean
+gegl_tile_damage (GeglTile *tile,
+                  guint64   damage)
+{
+  tile->damage |= damage;
+
+  if (! ~tile->damage)
+    {
+      gegl_tile_void (tile);
+
+      return TRUE;
+    }
+  else
+    {
+      if (tile->z == 0)
+        gegl_tile_void_pyramid (tile, damage);
+
+      return FALSE;
+    }
 }
 
 gboolean gegl_tile_store (GeglTile *tile)
@@ -357,7 +423,7 @@ gboolean gegl_tile_store (GeglTile *tile)
   gboolean ret;
   if (gegl_tile_is_stored (tile))
     return TRUE;
-  if (tile->tile_storage == NULL)
+  if (tile->tile_storage == NULL || tile->damage)
     return FALSE;
 
   if (gegl_config_threads()>1)


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