[gimp] app: move all special-case mode processing optimizations to GimpOperationLayerMode
- From: N/A <ell src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gimp] app: move all special-case mode processing optimizations to GimpOperationLayerMode
- Date: Thu, 2 Feb 2017 22:45:22 +0000 (UTC)
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]