[gegl] buffer: use empty tiles when filling buffer with 0-valued color



commit b2345ad0203c26a186bc01f9529a031de1d40662
Author: Ell <ell_se yahoo com>
Date:   Fri Nov 30 05:31:29 2018 -0500

    buffer: use empty tiles when filling buffer with 0-valued color
    
    In gegl_buffer_set_color_from_pixel(), if the pixel data, after
    conversion to the buffer format, is fully zeroed, use clones of the
    global empty tile for filling whole tiles, instead of creating a
    new 0-filled tile.  This allows us to share memory with the global
    empty tile, and makes uncloning the affected tiles more efficient.
    
    Note that we deliberately don't just clear the corresponding area
    of the buffer in this case, and make sure that there are actual
    empty tiles in the requested area, to stay on the safe side (mostly
    w.r.t. user-provided tile handlers, which may create non-zero tiles
    when the underlying handler returns a NULL tile).

 gegl/buffer/gegl-buffer-access.c      |  37 +++++++++----
 gegl/buffer/gegl-tile-handler-empty.c | 100 +++++++++++++++++-----------------
 gegl/buffer/gegl-tile-handler-empty.h |   2 +
 3 files changed, 78 insertions(+), 61 deletions(-)
---
diff --git a/gegl/buffer/gegl-buffer-access.c b/gegl/buffer/gegl-buffer-access.c
index 05bcdd2b1..eb4c6e97f 100644
--- a/gegl/buffer/gegl-buffer-access.c
+++ b/gegl/buffer/gegl-buffer-access.c
@@ -33,6 +33,7 @@
 #include "gegl-buffer.h"
 #include "gegl-buffer-private.h"
 #include "gegl-tile-storage.h"
+#include "gegl-tile-handler-empty.h"
 #include "gegl-sampler.h"
 #include "gegl-tile-backend.h"
 #include "gegl-buffer-iterator.h"
@@ -2880,26 +2881,40 @@ gegl_buffer_set_color_from_pixel_tile (GeglBuffer            *dst,
 {
   GeglTile *tile;
 
-  if (! data->tile)
+  if (data->tile)
     {
-      data->tile = gegl_tile_new (dst->tile_storage->tile_size);
+      tile = gegl_tile_dup (data->tile);
+    }
+  else
+    {
+      gint tile_size = dst->tile_storage->tile_size;
+
+      if (gegl_memeq_zero (data->pixel, data->bpp))
+        {
+          tile = gegl_tile_handler_empty_new_tile (tile_size);
+        }
+      else
+        {
+          tile = gegl_tile_new (tile_size);
 
-      gegl_tile_lock (data->tile);
+          gegl_tile_lock (tile);
 
-      gegl_memset_pattern (gegl_tile_get_data (data->tile),
-                           data->pixel,
-                           data->bpp,
-                           dst->tile_storage->tile_size / data->bpp);
+          gegl_memset_pattern (gegl_tile_get_data (tile),
+                               data->pixel,
+                               data->bpp,
+                               tile_size / data->bpp);
 
-      gegl_tile_unlock (data->tile);
+          gegl_tile_unlock (tile);
+        }
     }
 
-  tile = gegl_tile_dup (data->tile);
-
   gegl_tile_handler_cache_insert (dst->tile_storage->cache, tile,
                                   tile_x, tile_y, 0);
 
-  gegl_tile_unref (tile);
+  if (data->tile)
+    gegl_tile_unref (tile);
+  else
+    data->tile = tile;
 }
 
 static void
diff --git a/gegl/buffer/gegl-tile-handler-empty.c b/gegl/buffer/gegl-tile-handler-empty.c
index 9c2d0a860..23c45b594 100644
--- a/gegl/buffer/gegl-tile-handler-empty.c
+++ b/gegl/buffer/gegl-tile-handler-empty.c
@@ -38,55 +38,6 @@ finalize (GObject *object)
   G_OBJECT_CLASS (gegl_tile_handler_empty_parent_class)->finalize (object);
 }
 
-static GeglTile *
-_new_empty_tile (const gint tile_size)
-{
-  static GeglTile   *common_tile = NULL;
-  static const gint  common_empty_size = sizeof (gdouble) * 4 * 128 * 128;
-
-  GeglTile *tile;
-
-  if (tile_size > common_empty_size)
-    {
-      /* The tile size is too big to use the shared buffer */
-      tile = gegl_tile_new (tile_size);
-
-      memset (gegl_tile_get_data (tile), 0x00, tile_size);
-      tile->is_zero_tile = TRUE;
-    }
-  else
-    {
-      if (!g_atomic_pointer_get (&common_tile) &&
-          g_once_init_enter (&common_tile))
-        {
-          GeglTile *allocated_tile = gegl_tile_new_bare ();
-          guchar *allocated_buffer = gegl_malloc (common_empty_size);
-          memset (allocated_buffer, 0x00, common_empty_size);
-
-          allocated_tile->data           = allocated_buffer;
-          allocated_tile->destroy_notify = NULL;
-          allocated_tile->size           = common_empty_size;
-          allocated_tile->is_zero_tile   = TRUE;
-          allocated_tile->is_global_tile = TRUE;
-
-          /* avoid counting duplicates of the empty tile towards the total
-           * cache size, both since this is unnecessary, and since they may
-           * have different sizes, which is inconsistent with the duplicate-
-           * tracking cache logic.
-           */
-          (*gegl_tile_n_cached_clones (allocated_tile))++;
-
-          g_once_init_leave (&common_tile, allocated_tile);
-        }
-
-      tile = gegl_tile_dup (common_tile);
-
-      tile->size = tile_size;
-    }
-
-  return tile;
-}
-
 static GeglTile *
 get_tile (GeglTileSource *gegl_tile_source,
           gint            x,
@@ -105,7 +56,7 @@ get_tile (GeglTileSource *gegl_tile_source,
   if (!empty->tile)
     {
       gint tile_size = gegl_tile_backend_get_tile_size (empty->backend);
-      empty->tile    = _new_empty_tile (tile_size);
+      empty->tile    = gegl_tile_handler_empty_new_tile (tile_size);
     }
 
   tile = gegl_tile_handler_dup_tile (GEGL_TILE_HANDLER (empty),
@@ -157,3 +108,52 @@ gegl_tile_handler_empty_new (GeglTileBackend *backend)
 
   return (void*)empty;
 }
+
+GeglTile *
+gegl_tile_handler_empty_new_tile (gint tile_size)
+{
+  static GeglTile   *common_tile = NULL;
+  static const gint  common_empty_size = sizeof (gdouble) * 4 * 128 * 128;
+
+  GeglTile *tile;
+
+  if (tile_size > common_empty_size)
+    {
+      /* The tile size is too big to use the shared buffer */
+      tile = gegl_tile_new (tile_size);
+
+      memset (gegl_tile_get_data (tile), 0x00, tile_size);
+      tile->is_zero_tile = TRUE;
+    }
+  else
+    {
+      if (!g_atomic_pointer_get (&common_tile) &&
+          g_once_init_enter (&common_tile))
+        {
+          GeglTile *allocated_tile = gegl_tile_new_bare ();
+          guchar *allocated_buffer = gegl_malloc (common_empty_size);
+          memset (allocated_buffer, 0x00, common_empty_size);
+
+          allocated_tile->data           = allocated_buffer;
+          allocated_tile->destroy_notify = NULL;
+          allocated_tile->size           = common_empty_size;
+          allocated_tile->is_zero_tile   = TRUE;
+          allocated_tile->is_global_tile = TRUE;
+
+          /* avoid counting duplicates of the empty tile towards the total
+           * cache size, both since this is unnecessary, and since they may
+           * have different sizes, which is inconsistent with the duplicate-
+           * tracking cache logic.
+           */
+          (*gegl_tile_n_cached_clones (allocated_tile))++;
+
+          g_once_init_leave (&common_tile, allocated_tile);
+        }
+
+      tile = gegl_tile_dup (common_tile);
+
+      tile->size = tile_size;
+    }
+
+  return tile;
+}
diff --git a/gegl/buffer/gegl-tile-handler-empty.h b/gegl/buffer/gegl-tile-handler-empty.h
index 9b069f03e..b4ed66e4b 100644
--- a/gegl/buffer/gegl-tile-handler-empty.h
+++ b/gegl/buffer/gegl-tile-handler-empty.h
@@ -58,6 +58,8 @@ GType             gegl_tile_handler_empty_get_type (void) G_GNUC_CONST;
 
 GeglTileHandler * gegl_tile_handler_empty_new      (GeglTileBackend *backend);
 
+GeglTile        * gegl_tile_handler_empty_new_tile (gint tile_size);
+
 G_END_DECLS
 
 #endif


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