[gimp] app: optimize simple whole-drawable fill/clear



commit dd8268c0a25a8b5df5a06bd9b0d841f4c6915e2a
Author: Ell <ell_se yahoo com>
Date:   Sun Dec 2 02:59:24 2018 -0500

    app: optimize simple whole-drawable fill/clear
    
    In gimp_drawable_edit_fill(), when filling/clearing the whole
    drawable, without any special compositing (i.e., when there's no
    selection, the opacity is 100%, and the layer mode is trivial),
    fill/clear the drawable's buffer directly, without using an
    applicator.  This makes such operations much faster, especially in
    big images.

 app/core/gimpdrawable-edit.c | 179 ++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 158 insertions(+), 21 deletions(-)
---
diff --git a/app/core/gimpdrawable-edit.c b/app/core/gimpdrawable-edit.c
index 0cc3f45d67..b6bd153eeb 100644
--- a/app/core/gimpdrawable-edit.c
+++ b/app/core/gimpdrawable-edit.c
@@ -24,14 +24,131 @@
 
 #include "operations/layer-modes/gimp-layer-modes.h"
 
+#include "gegl/gimp-gegl-loops.h"
+
+#include "gimpchannel.h"
 #include "gimpdrawable.h"
 #include "gimpdrawable-edit.h"
+#include "gimpdrawableundo.h"
 #include "gimpcontext.h"
 #include "gimpfilloptions.h"
+#include "gimpimage.h"
+#include "gimpimage-undo.h"
+#include "gimppattern.h"
+#include "gimptempbuf.h"
 
 #include "gimp-intl.h"
 
 
+/*  local function prototypes  */
+
+static gboolean   gimp_drawable_edit_can_fill_direct (GimpDrawable    *drawable,
+                                                      GimpFillOptions *options);
+static void       gimp_drawable_edit_fill_direct     (GimpDrawable    *drawable,
+                                                      GimpFillOptions *options,
+                                                      const gchar     *undo_desc);
+
+
+/*  private functions  */
+
+static gboolean
+gimp_drawable_edit_can_fill_direct (GimpDrawable    *drawable,
+                                    GimpFillOptions *options)
+{
+  GimpImage              *image;
+  GimpContext            *context;
+  gdouble                 opacity;
+  GimpLayerMode           mode;
+  GimpLayerCompositeMode  composite_mode;
+
+  image          = gimp_item_get_image (GIMP_ITEM (drawable));
+  context        = GIMP_CONTEXT (options);
+  opacity        = gimp_context_get_opacity (context);
+  mode           = gimp_context_get_paint_mode (context);
+  composite_mode = gimp_layer_mode_get_paint_composite_mode (mode);
+
+  if (gimp_channel_is_empty (gimp_image_get_mask (image)) &&
+      opacity == GIMP_OPACITY_OPAQUE                      &&
+      gimp_layer_mode_is_trivial (mode)                   &&
+      (gimp_layer_mode_is_subtractive (mode)              ||
+       (gimp_layer_mode_get_included_region (mode, composite_mode) &
+        GIMP_LAYER_COMPOSITE_REGION_SOURCE)))
+    {
+      gboolean source_has_alpha = FALSE;
+
+      if (gimp_fill_options_get_style (options) == GIMP_FILL_STYLE_PATTERN &&
+          ! gimp_layer_mode_is_subtractive (mode))
+        {
+          GimpPattern *pattern;
+          const Babl  *format;
+
+          pattern = gimp_context_get_pattern (context);
+          format  = gimp_temp_buf_get_format (gimp_pattern_get_mask (pattern));
+
+          source_has_alpha = babl_format_has_alpha (format);
+        }
+
+      return ! source_has_alpha;
+    }
+
+  return FALSE;
+}
+
+static void
+gimp_drawable_edit_fill_direct (GimpDrawable    *drawable,
+                                GimpFillOptions *options,
+                                const gchar     *undo_desc)
+{
+  GeglBuffer       *buffer;
+  GimpImage        *image;
+  GimpContext      *context;
+  GimpDrawableUndo *undo;
+  gdouble           opacity;
+  GimpLayerMode     mode;
+  GimpLayerMode     composite_mode;
+  gint              width;
+  gint              height;
+
+  buffer         = gimp_drawable_get_buffer (drawable);
+  image          = gimp_item_get_image (GIMP_ITEM (drawable));
+  context        = GIMP_CONTEXT (options);
+  opacity        = gimp_context_get_opacity (context);
+  mode           = gimp_context_get_paint_mode (context);
+  composite_mode = gimp_layer_mode_get_paint_composite_mode (mode);
+  width          = gimp_item_get_width  (GIMP_ITEM (drawable));
+  height         = gimp_item_get_height (GIMP_ITEM (drawable));
+
+  gimp_drawable_push_undo (drawable, undo_desc,
+                           NULL, 0, 0, width, height);
+
+  if (! gimp_layer_mode_is_subtractive (mode))
+    gimp_fill_options_fill_buffer (options, drawable, buffer, 0, 0);
+  else
+    gimp_gegl_clear (buffer, NULL);
+
+  undo = GIMP_DRAWABLE_UNDO (gimp_image_undo_get_fadeable (image));
+
+  if (undo)
+    {
+      undo->paint_mode      = mode;
+      undo->blend_space     = GIMP_LAYER_COLOR_SPACE_AUTO;
+      undo->composite_space = GIMP_LAYER_COLOR_SPACE_AUTO;
+      undo->composite_mode  = composite_mode;
+      undo->opacity         = opacity;
+
+      if (! gimp_layer_mode_is_subtractive (mode))
+        {
+          undo->applied_buffer = gegl_buffer_dup (buffer);
+        }
+      else
+        {
+          undo->applied_buffer = gimp_fill_options_create_buffer (
+            options, drawable, GEGL_RECTANGLE (0, 0, width, height), 0, 0);
+        }
+    }
+}
+
+
 /*  public functions  */
 
 void
@@ -63,36 +180,56 @@ gimp_drawable_edit_fill (GimpDrawable    *drawable,
                          GimpFillOptions *options,
                          const gchar     *undo_desc)
 {
-  GeglBuffer  *buffer;
-  gint         x, y, width, height;
+  gint x, y, width, height;
 
   g_return_if_fail (GIMP_IS_DRAWABLE (drawable));
   g_return_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)));
   g_return_if_fail (GIMP_IS_FILL_OPTIONS (options));
 
-  if (! gimp_item_mask_intersect (GIMP_ITEM (drawable), &x, &y, &width, &height))
-    return;  /*  nothing to do, but the fill succeeded  */
-
-  buffer = gimp_fill_options_create_buffer (options, drawable,
-                                            GEGL_RECTANGLE (0, 0,
-                                                            width, height),
-                                            -x, -y);
+  if (! gimp_item_mask_intersect (GIMP_ITEM (drawable),
+                                  &x, &y, &width, &height))
+    {
+      return;  /*  nothing to do, but the fill succeeded  */
+    }
 
   if (! undo_desc)
     undo_desc = gimp_fill_options_get_undo_desc (options);
 
-  gimp_drawable_apply_buffer (drawable, buffer,
-                              GEGL_RECTANGLE (0, 0, width, height),
-                              TRUE, undo_desc,
-                              gimp_context_get_opacity (GIMP_CONTEXT (options)),
-                              gimp_context_get_paint_mode (GIMP_CONTEXT (options)),
-                              GIMP_LAYER_COLOR_SPACE_AUTO,
-                              GIMP_LAYER_COLOR_SPACE_AUTO,
-                              gimp_layer_mode_get_paint_composite_mode (
-                                gimp_context_get_paint_mode (GIMP_CONTEXT (options))),
-                              NULL, x, y);
-
-  g_object_unref (buffer);
+  /* check if we can fill the drawable's buffer directly */
+  if (gimp_drawable_edit_can_fill_direct (drawable, options))
+    {
+      gimp_drawable_edit_fill_direct (drawable, options, undo_desc);
+    }
+  else
+    {
+      GeglBuffer    *buffer;
+      GimpContext   *context;
+      gdouble        opacity;
+      GimpLayerMode  mode;
+      GimpLayerMode  composite_mode;
+
+      context        = GIMP_CONTEXT (options);
+      opacity        = gimp_context_get_opacity (context);
+      mode           = gimp_context_get_paint_mode (context);
+      composite_mode = gimp_layer_mode_get_paint_composite_mode (mode);
+
+      buffer = gimp_fill_options_create_buffer (options, drawable,
+                                                GEGL_RECTANGLE (0, 0,
+                                                                width, height),
+                                                -x, -y);
+
+      gimp_drawable_apply_buffer (drawable, buffer,
+                                  GEGL_RECTANGLE (0, 0, width, height),
+                                  TRUE, undo_desc,
+                                  opacity,
+                                  mode,
+                                  GIMP_LAYER_COLOR_SPACE_AUTO,
+                                  GIMP_LAYER_COLOR_SPACE_AUTO,
+                                  composite_mode,
+                                  NULL, x, y);
+
+      g_object_unref (buffer);
+    }
 
   gimp_drawable_update (drawable, x, y, width, height);
 }


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