mirror of https://github.com/GNOME/gimp.git
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.
This commit is contained in:
parent
e957347dd6
commit
1214d4acf1
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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_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_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);
|
||||
GObject *input;
|
||||
GObject *aux;
|
||||
gboolean has_input;
|
||||
gboolean has_aux;
|
||||
|
||||
if (point->opacity == 0.0 ||
|
||||
! gegl_operation_context_get_object (context, "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;
|
||||
|
||||
/* get the raw values, this does not increase the reference count */
|
||||
input = gegl_operation_context_get_object (context, "input");
|
||||
|
||||
if (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))
|
||||
{
|
||||
gegl_operation_context_set_object (context, "output", input);
|
||||
GimpLayerModeAffectMask affect_mask;
|
||||
|
||||
affect_mask = gimp_operation_layer_mode_get_affect_mask (point);
|
||||
|
||||
/* ... 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
|
||||
{
|
||||
/* ... 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);
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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__ */
|
||||
|
|
Loading…
Reference in New Issue