[gimp] app: speed up gradient rendering a lot



commit 9dbf919d46aeb9604404d551979b7dd511cb0a8f
Author: Michael Natterer <mitch gimp org>
Date:   Wed Apr 18 01:11:33 2018 +0200

    app: speed up gradient rendering a lot
    
    by using a cache of colors that is calculated once, instead of
    calling gimp_gradient_get_color_at() for each rendered pixel.

 app/core/gimpdrawable-gradient.c       |    9 ++
 app/operations/gimpoperationgradient.c |  159 +++++++++++++-------------------
 app/operations/gimpoperationgradient.h |    4 +
 app/tools/gimpgradienttool.c           |   35 ++++++-
 4 files changed, 105 insertions(+), 102 deletions(-)
---
diff --git a/app/core/gimpdrawable-gradient.c b/app/core/gimpdrawable-gradient.c
index 696d7a6..8d56997 100644
--- a/app/core/gimpdrawable-gradient.c
+++ b/app/core/gimpdrawable-gradient.c
@@ -91,6 +91,15 @@ gimp_drawable_gradient (GimpDrawable                *drawable,
         gimp_drawable_gradient_shapeburst_distmap (drawable, metric,
                                                    GEGL_RECTANGLE (x, y, width, height),
                                                    progress);
+
+      /*  in shapeburst mode, make sure the "line" is long enough to
+       *  span across the selection, so the operation's cache has the
+       *  right size
+       */
+      startx = x;
+      starty = y;
+      endx   = x + width;
+      endy   = y + height;
     }
 
   render = gegl_node_new_child (NULL,
diff --git a/app/operations/gimpoperationgradient.c b/app/operations/gimpoperationgradient.c
index 8382285..69c5bbe 100644
--- a/app/operations/gimpoperationgradient.c
+++ b/app/operations/gimpoperationgradient.c
@@ -36,8 +36,6 @@
 #include "gimpoperationgradient.h"
 
 
-//#define USE_GRADIENT_CACHE 1
-
 enum
 {
   PROP_0,
@@ -60,25 +58,16 @@ enum
 
 typedef struct
 {
-  GimpGradient                *gradient;
-  gboolean                     reverse;
-  GimpGradientBlendColorSpace  blend_color_space;
-#ifdef USE_GRADIENT_CACHE
-  GimpRGB                     *gradient_cache;
-  gint                         gradient_cache_size;
-#else
-  GimpGradientSegment         *last_seg;
-#endif
-  gdouble                      offset;
-  gdouble                      sx, sy;
-  GimpGradientType             gradient_type;
-  gdouble                      dist;
-  gdouble                      vec[2];
-  GimpRepeatMode               repeat;
-  GimpRGB                      leftmost_color;
-  GimpRGB                      rightmost_color;
-  GRand                       *seed;
-  GeglBuffer                  *dist_buffer;
+  GimpGradient      *gradient;
+  GimpRGB           *gradient_cache;
+  gint               gradient_cache_size;
+  gdouble            offset;
+  gdouble            sx, sy;
+  GimpGradientType   gradient_type;
+  gdouble            dist;
+  gdouble            vec[2];
+  GimpRepeatMode     repeat;
+  GeglBuffer        *dist_buffer;
 } RenderBlendData;
 
 
@@ -335,6 +324,7 @@ gimp_operation_gradient_dispose (GObject *object)
 
   g_clear_object (&self->gradient);
   g_clear_object (&self->context);
+  g_clear_pointer (&self->gradient_cache, g_free);
 
   G_OBJECT_CLASS (parent_class)->dispose (object);
 }
@@ -509,7 +499,23 @@ gimp_operation_gradient_set_property (GObject      *object,
 static void
 gimp_operation_gradient_prepare (GeglOperation *operation)
 {
+  GimpOperationGradient *self = GIMP_OPERATION_GRADIENT (operation);
+  gint                   cache_size;
+
   gegl_operation_set_format (operation, "output", babl_format ("R'G'B'A float"));
+
+  cache_size = ceil (sqrt (SQR (self->start_x - self->end_x) +
+                           SQR (self->start_y - self->end_y))) * 4;
+
+  if (cache_size != self->gradient_cache_size)
+    {
+      g_clear_pointer (&self->gradient_cache, g_free);
+
+      self->gradient_cache      = g_new0 (GimpRGB, cache_size);
+      self->gradient_cache_size = cache_size;
+    }
+
+  self->gradient_cache_valid = FALSE;
 }
 
 static GeglRectangle
@@ -900,7 +906,6 @@ gradient_render_pixel (gdouble   x,
 
   switch (rbd->repeat)
     {
-    case GIMP_REPEAT_TRUNCATE:
     case GIMP_REPEAT_NONE:
       break;
 
@@ -922,30 +927,21 @@ gradient_render_pixel (gdouble   x,
           factor = 1.0 - factor;
       }
       break;
+
+    case GIMP_REPEAT_TRUNCATE:
+      if (factor < 0.0 || factor > 1.0)
+        {
+          gimp_rgba_set (color, 0.0, 0.0, 0.0, 0.0);
+          return;
+        }
+      break;
     }
 
   /* Blend the colors */
 
-  if (factor <= 0.0)
-    {
-      *color = rbd->leftmost_color;
-    }
-  else if (factor >= 1.0)
-    {
-      *color = rbd->rightmost_color;
-    }
-  else
-    {
-#ifdef USE_GRADIENT_CACHE
-      *color = rbd->gradient_cache[(gint) (factor * (rbd->gradient_cache_size - 1))];
-#else
-      rbd->last_seg = gimp_gradient_get_color_at (rbd->gradient, NULL,
-                                                  rbd->last_seg, factor,
-                                                  rbd->reverse,
-                                                  rbd->blend_color_space,
-                                                  color);
-#endif
-    }
+  factor = CLAMP (factor, 0.0, 1.0);
+
+  *color = rbd->gradient_cache[(gint) (factor * (rbd->gradient_cache_size - 1))];
 }
 
 static void
@@ -1008,35 +1004,31 @@ gimp_operation_gradient_process (GeglOperation       *operation,
 
   RenderBlendData rbd = { 0, };
 
-  rbd.gradient          = NULL;
-  rbd.reverse           = self->gradient_reverse;
-  rbd.blend_color_space = self->gradient_blend_color_space;
+  if (! self->gradient)
+    return TRUE;
 
-  if (self->gradient)
-    rbd.gradient = g_object_ref (self->gradient);
-  else
-    rbd.gradient = GIMP_GRADIENT (gimp_gradient_new (NULL, "Gradient-Temp"));
+  if (! self->gradient_cache_valid)
+    {
+      GimpGradientSegment *last_seg = NULL;
+      gint                 i;
 
-#ifdef USE_GRADIENT_CACHE
-  {
-    GimpGradientSegment *last_seg = NULL;
-    gint                 i;
+      for (i = 0; i < self->gradient_cache_size; i++)
+        {
+          gdouble factor = (gdouble) i / (gdouble) (self->gradient_cache_size - 1);
 
-    rbd.gradient_cache_size = ceil (sqrt (SQR (sx - ex) + SQR (sy - ey)));
-    rbd.gradient_cache      = g_new0 (GimpRGB, rbd.gradient_cache_size);
+          last_seg = gimp_gradient_get_color_at (self->gradient, NULL, last_seg,
+                                                 factor,
+                                                 self->gradient_reverse,
+                                                 self->gradient_blend_color_space,
+                                                 self->gradient_cache + i);
+        }
 
-    for (i = 0; i < rbd.gradient_cache_size; i++)
-      {
-        gdouble factor = (gdouble) i / (gdouble) (rbd.gradient_cache_size - 1);
+      self->gradient_cache_valid = TRUE;
+    }
 
-        last_seg = gimp_gradient_get_color_at (rbd.gradient, NULL, last_seg,
-                                               factor,
-                                               rbd.reverse,
-                                               rbd.blend_color_space,
-                                               rbd.gradient_cache + i);
-      }
-  }
-#endif
+  rbd.gradient            = self->gradient;
+  rbd.gradient_cache      = self->gradient_cache;
+  rbd.gradient_cache_size = self->gradient_cache_size;
 
   /* Calculate type-specific parameters */
 
@@ -1086,26 +1078,6 @@ gimp_operation_gradient_process (GeglOperation       *operation,
   rbd.gradient_type = self->gradient_type;
   rbd.repeat        = self->gradient_repeat;
 
-  if (rbd.repeat == GIMP_REPEAT_NONE)
-    {
-      gimp_gradient_segment_get_left_flat_color  (rbd.gradient, NULL,
-                                                  rbd.gradient->segments,
-                                                  &rbd.leftmost_color);
-      gimp_gradient_segment_get_right_flat_color (rbd.gradient, NULL,
-                                                  gimp_gradient_segment_get_last (
-                                                    rbd.gradient->segments),
-                                                  &rbd.rightmost_color);
-
-      if (rbd.reverse)
-        {
-          GimpRGB temp;
-
-          temp                = rbd.leftmost_color;
-          rbd.leftmost_color  = rbd.rightmost_color;
-          rbd.rightmost_color = temp;
-        }
-    }
-
   /* Render the gradient! */
 
   if (self->supersample)
@@ -1137,6 +1109,7 @@ gimp_operation_gradient_process (GeglOperation       *operation,
     {
       GeglBufferIterator *iter;
       GeglRectangle      *roi;
+      GRand              *seed = NULL;
 
       iter = gegl_buffer_iterator_new (output, result, 0,
                                        babl_format ("R'G'B'A float"),
@@ -1144,7 +1117,7 @@ gimp_operation_gradient_process (GeglOperation       *operation,
       roi = &iter->roi[0];
 
       if (self->dither)
-        rbd.seed = g_rand_new ();
+        seed = g_rand_new ();
 
       while (gegl_buffer_iterator_next (iter))
         {
@@ -1153,9 +1126,9 @@ gimp_operation_gradient_process (GeglOperation       *operation,
           gint    endy = roi->y + roi->height;
           gint    x, y;
 
-          if (rbd.seed)
+          if (seed)
             {
-              GRand *dither_rand = g_rand_new_with_seed (g_rand_int (rbd.seed));
+              GRand *dither_rand = g_rand_new_with_seed (g_rand_int (seed));
 
               for (y = roi->y; y < endy; y++)
                 for (x = roi->x; x < endx; x++)
@@ -1201,14 +1174,8 @@ gimp_operation_gradient_process (GeglOperation       *operation,
         }
 
       if (self->dither)
-        g_rand_free (rbd.seed);
+        g_rand_free (seed);
     }
 
-#ifdef USE_GRADIENT_CACHE
-  g_free (rbd.gradient_cache);
-#endif
-
-  g_object_unref (rbd.gradient);
-
   return TRUE;
 }
diff --git a/app/operations/gimpoperationgradient.h b/app/operations/gimpoperationgradient.h
index b63686a..5f29464 100644
--- a/app/operations/gimpoperationgradient.h
+++ b/app/operations/gimpoperationgradient.h
@@ -55,6 +55,10 @@ struct _GimpOperationGradient
   gdouble                       supersample_threshold;
 
   gboolean                      dither;
+
+  GimpRGB                      *gradient_cache;
+  gint                          gradient_cache_size;
+  gboolean                      gradient_cache_valid;
 };
 
 struct _GimpOperationGradientClass
diff --git a/app/tools/gimpgradienttool.c b/app/tools/gimpgradienttool.c
index b66b15b..d4278aa 100644
--- a/app/tools/gimpgradienttool.c
+++ b/app/tools/gimpgradienttool.c
@@ -909,12 +909,35 @@ gimp_gradient_tool_update_graph (GimpGradientTool *gradient_tool)
   else
 #endif
     {
-      gegl_node_set (gradient_tool->render_node,
-                     "start_x", gradient_tool->start_x - off_x,
-                     "start_y", gradient_tool->start_y - off_y,
-                     "end_x",   gradient_tool->end_x - off_x,
-                     "end_y",   gradient_tool->end_y - off_y,
-                     NULL);
+      if (gimp_gradient_tool_is_shapeburst (gradient_tool))
+        {
+          /*  in shapeburst mode, make sure the "line" is long enough
+           *  to span across the selection, so the operation's cache
+           *  has the right size
+           */
+
+          GimpImage *image = gimp_display_get_image (tool->display);
+          gdouble    x, y, w, h;
+
+          gimp_item_bounds_f (GIMP_ITEM (gimp_image_get_mask (image)),
+                              &x, &y, &w, &h);
+
+          gegl_node_set (gradient_tool->render_node,
+                         "start-x", x,
+                         "start-y", y,
+                         "end-x",   x + w,
+                         "end-y",   y + h,
+                         NULL);
+        }
+      else
+        {
+          gegl_node_set (gradient_tool->render_node,
+                         "start-x", gradient_tool->start_x - off_x,
+                         "start-y", gradient_tool->start_y - off_y,
+                         "end-x",   gradient_tool->end_x - off_x,
+                         "end-y",   gradient_tool->end_y - off_y,
+                         NULL);
+        }
     }
 }
 


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