[gimp] app: move all special-case mode processing optimizations to GimpOperationLayerMode



commit 1214d4acf1d7e954ef1f95ac7c5932141865e725
Author: Ell <ell_se yahoo com>
Date:   Thu Feb 2 10:53:09 2017 -0500

    app: move all special-case mode processing optimizations to GimpOperationLayerMode
    
    Stuff like passing "input" directly if "aux"'s opacity is 0, etc.
    Used to be partly handled by normal mode, even though it applies
    to other modes too.
    
    Adjust the logic for the new compositing modes.
    
    Add a GimpLayerModeAffectMask enum, and a corresponding
    get_affect_mask() function to GimpOperationLayerMode, which
    specifies which of the op's inputs, if any, are affected by the
    mode, apart from the overlapping regions.  Most modes affect only
    the overlapping regions, but dissolve and replace also affect the
    rest of the input.  This information is used for determining if
    the optimizations are applicable.

 app/operations/layer-modes/gimpoperationdissolve.c |   13 ++
 .../layer-modes/gimpoperationlayermode.c           |  172 +++++++++++++++++---
 .../layer-modes/gimpoperationlayermode.h           |   12 ++-
 app/operations/layer-modes/gimpoperationnormal.c   |   62 -------
 app/operations/layer-modes/gimpoperationreplace.c  |   26 +++-
 app/operations/operations-enums.h                  |   13 ++
 6 files changed, 208 insertions(+), 90 deletions(-)
---
diff --git a/app/operations/layer-modes/gimpoperationdissolve.c 
b/app/operations/layer-modes/gimpoperationdissolve.c
index c71019d..bd59ea8 100644
--- a/app/operations/layer-modes/gimpoperationdissolve.c
+++ b/app/operations/layer-modes/gimpoperationdissolve.c
@@ -32,6 +32,9 @@
 #define RANDOM_TABLE_SIZE 4096
 
 
+static GimpLayerModeAffectMask gimp_operation_dissolve_get_affect_mask (GimpOperationLayerMode *layer_mode);
+
+
 G_DEFINE_TYPE (GimpOperationDissolve, gimp_operation_dissolve,
                GIMP_TYPE_OPERATION_LAYER_MODE)
 
@@ -44,11 +47,13 @@ gimp_operation_dissolve_class_init (GimpOperationDissolveClass *klass)
 {
   GeglOperationClass               *operation_class;
   GeglOperationPointComposer3Class *point_composer_class;
+  GimpOperationLayerModeClass      *layer_mode_class;
   GRand                            *gr;
   gint                              i;
 
   operation_class      = GEGL_OPERATION_CLASS (klass);
   point_composer_class = GEGL_OPERATION_POINT_COMPOSER3_CLASS (klass);
+  layer_mode_class     = GIMP_OPERATION_LAYER_MODE_CLASS (klass);
 
   gegl_operation_class_set_keys (operation_class,
                                  "name",        "gimp:dissolve",
@@ -58,6 +63,8 @@ gimp_operation_dissolve_class_init (GimpOperationDissolveClass *klass)
 
   point_composer_class->process = gimp_operation_dissolve_process;
 
+  layer_mode_class->get_affect_mask = gimp_operation_dissolve_get_affect_mask;
+
   /* generate a table of random seeds */
   gr = g_rand_new_with_seed (314159265);
   for (i = 0; i < RANDOM_TABLE_SIZE; i++)
@@ -133,3 +140,9 @@ gimp_operation_dissolve_process (GeglOperation       *op,
 
   return TRUE;
 }
+
+static GimpLayerModeAffectMask
+gimp_operation_dissolve_get_affect_mask (GimpOperationLayerMode *layer_mode)
+{
+  return GIMP_LAYER_MODE_AFFECT_SRC;
+}
diff --git a/app/operations/layer-modes/gimpoperationlayermode.c 
b/app/operations/layer-modes/gimpoperationlayermode.c
index bed3c4b..2d547de 100644
--- a/app/operations/layer-modes/gimpoperationlayermode.c
+++ b/app/operations/layer-modes/gimpoperationlayermode.c
@@ -44,21 +44,24 @@ enum
 };
 
 
-static void     gimp_operation_layer_mode_set_property (GObject              *object,
-                                                        guint                 property_id,
-                                                        const GValue         *value,
-                                                        GParamSpec           *pspec);
-static void     gimp_operation_layer_mode_get_property (GObject              *object,
-                                                        guint                 property_id,
-                                                        GValue               *value,
-                                                        GParamSpec           *pspec);
-
-static void     gimp_operation_layer_mode_prepare      (GeglOperation        *operation);
-static gboolean gimp_operation_layer_mode_process      (GeglOperation        *operation,
-                                                        GeglOperationContext *context,
-                                                        const gchar          *output_prop,
-                                                        const GeglRectangle  *result,
-                                                        gint                  level);
+static void     gimp_operation_layer_mode_set_property (GObject                *object,
+                                                        guint                   property_id,
+                                                        const GValue           *value,
+                                                        GParamSpec             *pspec);
+static void     gimp_operation_layer_mode_get_property (GObject                *object,
+                                                        guint                   property_id,
+                                                        GValue                 *value,
+                                                        GParamSpec             *pspec);
+
+static void     gimp_operation_layer_mode_prepare      (GeglOperation          *operation);
+static gboolean gimp_operation_layer_mode_process      (GeglOperation          *operation,
+                                                        GeglOperationContext   *context,
+                                                        const gchar            *output_prop,
+                                                        const GeglRectangle    *result,
+                                                        gint                    level);
+
+static GimpLayerModeAffectMask
+        gimp_operation_layer_mode_real_get_affect_mask (GimpOperationLayerMode *layer_mode);
 
 G_DEFINE_TYPE (GimpOperationLayerMode, gimp_operation_layer_mode,
                GEGL_TYPE_OPERATION_POINT_COMPOSER3)
@@ -152,6 +155,8 @@ gimp_operation_layer_mode_class_init (GimpOperationLayerModeClass *klass)
   operation_class->process       = gimp_operation_layer_mode_process;
   point_composer3_class->process = gimp_operation_layer_mode_process_pixels;
 
+  klass->get_affect_mask = gimp_operation_layer_mode_real_get_affect_mask;
+
   g_object_class_install_property (object_class, PROP_LAYER_MODE,
                                    g_param_spec_enum ("layer-mode",
                                                       NULL, NULL,
@@ -318,21 +323,115 @@ gimp_operation_layer_mode_process (GeglOperation        *operation,
                                    gint                  level)
 {
   GimpOperationLayerMode *point = GIMP_OPERATION_LAYER_MODE (operation);
-
-  if (point->opacity == 0.0 ||
-      ! gegl_operation_context_get_object (context, "aux"))
+  GObject                *input;
+  GObject                *aux;
+  gboolean                has_input;
+  gboolean                has_aux;
+
+  /* get the raw values.  this does not increase the reference count. */
+  input = gegl_operation_context_get_object (context, "input");
+  aux   = gegl_operation_context_get_object (context, "aux");
+
+  /* disregard 'input' if it's not included in the roi. */
+  has_input =
+    input &&
+    gegl_rectangle_intersect (NULL,
+                              gegl_buffer_get_extent (GEGL_BUFFER (input)),
+                              result);
+
+  /* disregard 'aux' if it's not included in the roi, or if it's fully
+   * transparent.
+   */
+  has_aux =
+    aux &&
+    point->opacity != 0.0 &&
+    gegl_rectangle_intersect (NULL,
+                              gegl_buffer_get_extent (GEGL_BUFFER (aux)),
+                              result);
+
+  /* if there's no 'input' ... */
+  if (! has_input)
     {
-      GObject *input;
+      /* ... and there's 'aux', and the composite mode includes it ... */
+      if (has_aux &&
+          (point->composite_mode == GIMP_LAYER_COMPOSITE_SRC_OVER ||
+           point->composite_mode == GIMP_LAYER_COMPOSITE_DST_ATOP))
+        {
+          GimpLayerModeAffectMask affect_mask;
 
-      /* get the raw values, this does not increase the reference count */
-      input = gegl_operation_context_get_object (context, "input");
+          affect_mask = gimp_operation_layer_mode_get_affect_mask (point);
 
-      if (input)
+          /* ... and the op doesn't otherwise affect 'aux', or changes its
+           * alpha ...
+           */
+          if (! (affect_mask & GIMP_LAYER_MODE_AFFECT_SRC) &&
+              point->opacity == 1.0                        &&
+              ! gegl_operation_context_get_object (context, "aux2"))
+            {
+              /* pass 'aux' directly as output; */
+              gegl_operation_context_set_object (context, "output", aux);
+              return TRUE;
+            }
+
+          /* otherwise, if the op affects 'aux', or changes its alpha, process
+           * it even though there's no 'input';
+           */
+        }
+      /* otherwise, there's no 'aux', or the composite mode doesn't include it,
+       * and so ...
+       */
+      else
         {
-          gegl_operation_context_set_object (context, "output", input);
+          /* ... the output is empty. */
+          gegl_operation_context_set_object (context, "output", NULL);
           return TRUE;
         }
     }
+  /* otherwise, if there's 'input' but no 'aux' ... */
+  else if (! has_aux)
+    {
+      /* ... and the composite mode includes 'input' ... */
+      if (point->composite_mode == GIMP_LAYER_COMPOSITE_SRC_OVER ||
+          point->composite_mode == GIMP_LAYER_COMPOSITE_SRC_ATOP)
+        {
+          GimpLayerModeAffectMask affect_mask;
+
+          affect_mask = gimp_operation_layer_mode_get_affect_mask (point);
+
+          /* ... and the op doesn't otherwise affect 'input' ... */
+          if (! (affect_mask & GIMP_LAYER_MODE_AFFECT_DST))
+            {
+              /* pass 'input' directly as output; */
+              gegl_operation_context_set_object (context, "output", input);
+              return TRUE;
+            }
+
+          /* otherwise, if the op affects 'input', process it even though
+           * there's no 'aux';
+           */
+        }
+
+      /* otherwise, the output is fully transparent, but we process it anyway
+       * to maintain the 'input' color values.
+       */
+    }
+
+  /* FIXME: we don't actually handle the case where one of the inputs
+   * is NULL -- it'll just segfault.  'input' is not expected to be NULL,
+   * but 'aux' might be, currently.
+   */
+  if (! input || ! aux)
+    {
+      GObject *empty = G_OBJECT (gegl_buffer_new (NULL, NULL));
+
+      if (! input) gegl_operation_context_set_object (context, "input", empty);
+      if (! aux)   gegl_operation_context_set_object (context, "aux",   empty);
+
+      if (! input && ! aux)
+        gegl_object_set_has_forked (G_OBJECT (empty));
+
+      g_object_unref (empty);
+    }
 
   /* chain up, which will create the needed buffers for our actual
    * process function
@@ -342,6 +441,29 @@ gimp_operation_layer_mode_process (GeglOperation        *operation,
                                                        level);
 }
 
+static GimpLayerModeAffectMask
+gimp_operation_layer_mode_real_get_affect_mask (GimpOperationLayerMode *layer_mode)
+{
+  /* most modes only affect the overlapping regions. */
+  return GIMP_LAYER_MODE_AFFECT_NONE;
+}
+
+
+/* public functions */
+
+
+GimpLayerModeAffectMask
+gimp_operation_layer_mode_get_affect_mask (GimpOperationLayerMode *layer_mode)
+{
+  g_return_val_if_fail (GIMP_IS_OPERATION_LAYER_MODE (layer_mode),
+                        GIMP_LAYER_MODE_AFFECT_NONE);
+
+  return GIMP_OPERATION_LAYER_MODE_GET_CLASS (layer_mode)->get_affect_mask (layer_mode);
+}
+
+
+/* compositing and blending functions */
+
 
 static inline GimpBlendFunc gimp_layer_mode_get_blend_fun (GimpLayerMode mode);
 
diff --git a/app/operations/layer-modes/gimpoperationlayermode.h 
b/app/operations/layer-modes/gimpoperationlayermode.h
index 545203f..9d69052 100644
--- a/app/operations/layer-modes/gimpoperationlayermode.h
+++ b/app/operations/layer-modes/gimpoperationlayermode.h
@@ -38,6 +38,14 @@ typedef struct _GimpOperationLayerModeClass GimpOperationLayerModeClass;
 struct _GimpOperationLayerModeClass
 {
   GeglOperationPointComposer3Class  parent_class;
+
+  /*  virtual functions  */
+
+  /* Returns the set of inputs that the layer mode affects, apart
+   * from the overlapping regions.  Returns an empty set by default,
+   * which is suitable for almost all layer modes.
+   */
+  GimpLayerModeAffectMask (* get_affect_mask) (GimpOperationLayerMode *layer_mode);
 };
 
 struct _GimpOperationLayerMode
@@ -54,7 +62,9 @@ struct _GimpOperationLayerMode
 };
 
 
-GType   gimp_operation_layer_mode_get_type (void) G_GNUC_CONST;
+GType                   gimp_operation_layer_mode_get_type        (void) G_GNUC_CONST;
+
+GimpLayerModeAffectMask gimp_operation_layer_mode_get_affect_mask (GimpOperationLayerMode *layer_mode);
 
 gboolean
 gimp_operation_layer_mode_process_pixels (GeglOperation       *operation,
diff --git a/app/operations/layer-modes/gimpoperationnormal.c 
b/app/operations/layer-modes/gimpoperationnormal.c
index 3495497..3053236 100644
--- a/app/operations/layer-modes/gimpoperationnormal.c
+++ b/app/operations/layer-modes/gimpoperationnormal.c
@@ -30,12 +30,6 @@
 #include "gimpoperationnormal.h"
 
 
-static gboolean gimp_operation_normal_parent_process (GeglOperation        *operation,
-                                                      GeglOperationContext *context,
-                                                      const gchar          *output_prop,
-                                                      const GeglRectangle  *result,
-                                                      gint                  level);
-
 G_DEFINE_TYPE (GimpOperationNormal, gimp_operation_normal,
                GIMP_TYPE_OPERATION_LAYER_MODE)
 
@@ -77,9 +71,6 @@ gimp_operation_normal_class_init (GimpOperationNormalClass *klass)
                                  "reference-composition", reference_xml,
                                  NULL);
 
-  operation_class->process     = gimp_operation_normal_parent_process;
-
-
   gimp_operation_normal_process = gimp_operation_normal_process_core;
 
 #if COMPILE_SSE2_INTRINISICS
@@ -100,59 +91,6 @@ gimp_operation_normal_init (GimpOperationNormal *self)
 {
 }
 
-static gboolean
-gimp_operation_normal_parent_process (GeglOperation        *operation,
-                                      GeglOperationContext *context,
-                                      const gchar          *output_prop,
-                                      const GeglRectangle  *result,
-                                      gint                  level)
-{
-  GimpOperationLayerMode *layer_mode = GIMP_OPERATION_LAYER_MODE (operation);
-
-  if (layer_mode->opacity == 1.0 &&
-      ! gegl_operation_context_get_object (context, "aux2"))
-    {
-      const GeglRectangle *in_extent  = NULL;
-      const GeglRectangle *aux_extent = NULL;
-      GObject             *input;
-      GObject             *aux;
-
-      /* get the raw values this does not increase the reference count */
-      input = gegl_operation_context_get_object (context, "input");
-      aux   = gegl_operation_context_get_object (context, "aux");
-
-      /* pass the input/aux buffers directly through if they are not
-       * overlapping
-       */
-      if (input)
-        in_extent = gegl_buffer_get_abyss (GEGL_BUFFER (input));
-
-      if (! input ||
-          (aux && ! gegl_rectangle_intersect (NULL, in_extent, result)))
-        {
-          gegl_operation_context_set_object (context, "output", aux);
-          return TRUE;
-        }
-
-      if (aux)
-        aux_extent = gegl_buffer_get_abyss (GEGL_BUFFER (aux));
-
-      if (! aux ||
-          (input && ! gegl_rectangle_intersect (NULL, aux_extent, result)))
-        {
-          gegl_operation_context_set_object (context, "output", input);
-          return TRUE;
-        }
-    }
-
-  /* chain up, which will create the needed buffers for our actual
-   * process function
-   */
-  return GEGL_OPERATION_CLASS (parent_class)->process (operation, context,
-                                                       output_prop, result,
-                                                       level);
-}
-
 gboolean
 gimp_operation_normal_process_core (GeglOperation       *op,
                                     void                *in_p,
diff --git a/app/operations/layer-modes/gimpoperationreplace.c 
b/app/operations/layer-modes/gimpoperationreplace.c
index 2b1597d..07a2c0a 100644
--- a/app/operations/layer-modes/gimpoperationreplace.c
+++ b/app/operations/layer-modes/gimpoperationreplace.c
@@ -27,6 +27,9 @@
 #include "gimpoperationreplace.h"
 
 
+static GimpLayerModeAffectMask gimp_operation_replace_get_affect_mask (GimpOperationLayerMode *layer_mode);
+
+
 G_DEFINE_TYPE (GimpOperationReplace, gimp_operation_replace,
                GIMP_TYPE_OPERATION_LAYER_MODE)
 
@@ -36,9 +39,11 @@ gimp_operation_replace_class_init (GimpOperationReplaceClass *klass)
 {
   GeglOperationClass               *operation_class;
   GeglOperationPointComposer3Class *point_class;
+  GimpOperationLayerModeClass      *layer_mode_class;
 
-  operation_class = GEGL_OPERATION_CLASS (klass);
-  point_class     = GEGL_OPERATION_POINT_COMPOSER3_CLASS (klass);
+  operation_class  = GEGL_OPERATION_CLASS (klass);
+  point_class      = GEGL_OPERATION_POINT_COMPOSER3_CLASS (klass);
+  layer_mode_class = GIMP_OPERATION_LAYER_MODE_CLASS (klass);
 
   gegl_operation_class_set_keys (operation_class,
                                  "name",        "gimp:replace",
@@ -46,6 +51,8 @@ gimp_operation_replace_class_init (GimpOperationReplaceClass *klass)
                                  NULL);
 
   point_class->process = gimp_operation_replace_process;
+
+  layer_mode_class->get_affect_mask = gimp_operation_replace_get_affect_mask;
 }
 
 static void
@@ -107,3 +114,18 @@ gimp_operation_replace_process (GeglOperation       *op,
 
   return TRUE;
 }
+
+static GimpLayerModeAffectMask
+gimp_operation_replace_get_affect_mask (GimpOperationLayerMode *layer_mode)
+{
+  GimpLayerModeAffectMask affect_mask = GIMP_LAYER_MODE_AFFECT_NONE;
+
+  if (layer_mode->opacity != 0.0)
+    affect_mask |= GIMP_LAYER_MODE_AFFECT_DST;
+
+  /* if opacity != 1.0, or we have a mask, thne we also affect SRC, but this is
+   * considered the case anyway, so no need for special handling.
+   */
+
+  return affect_mask;
+}
diff --git a/app/operations/operations-enums.h b/app/operations/operations-enums.h
index be1eb4e..0739562 100644
--- a/app/operations/operations-enums.h
+++ b/app/operations/operations-enums.h
@@ -47,4 +47,17 @@ typedef enum
 } GimpLayerCompositeMode;
 
 
+/*
+ * non-registered enums; register them if needed
+ */
+
+
+typedef enum  /*< pdb-skip, skip >*/
+{
+  GIMP_LAYER_MODE_AFFECT_NONE = 0,
+  GIMP_LAYER_MODE_AFFECT_DST  = 1 << 0,
+  GIMP_LAYER_MODE_AFFECT_SRC  = 1 << 1
+} GimpLayerModeAffectMask;
+
+
 #endif /* __OPERATIONS_ENUMS_H__ */


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