From d1a0c253c24dc2748fbe4951ecb5055647c17612 Mon Sep 17 00:00:00 2001 From: Ell Date: Fri, 17 Feb 2017 11:58:18 -0500 Subject: [PATCH] app: implement the different composite modes for normal mode --- .../layer-modes/gimpoperationnormal-sse2.c | 224 ++++++++++++++---- .../layer-modes/gimpoperationnormal-sse4.c | 221 +++++++++++++---- .../layer-modes/gimpoperationnormal.c | 171 +++++++++++-- 3 files changed, 510 insertions(+), 106 deletions(-) diff --git a/app/operations/layer-modes/gimpoperationnormal-sse2.c b/app/operations/layer-modes/gimpoperationnormal-sse2.c index b6ab493ff5..1adbd9088d 100644 --- a/app/operations/layer-modes/gimpoperationnormal-sse2.c +++ b/app/operations/layer-modes/gimpoperationnormal-sse2.c @@ -51,67 +51,209 @@ gimp_operation_normal_process_sse2 (GeglOperation *operation, } else { - gfloat opacity = ((GimpOperationLayerMode *)(operation))->opacity; - gfloat *mask = mask_p; - const __v4sf *v_in = (const __v4sf*) in; - const __v4sf *v_aux = (const __v4sf*) aux; - __v4sf *v_out = ( __v4sf*) out; + GimpOperationLayerMode *layer_mode = (GimpOperationLayerMode *) operation; + gfloat opacity = layer_mode->opacity; + gfloat *mask = mask_p; + const __v4sf *v_in = (const __v4sf*) in; + const __v4sf *v_aux = (const __v4sf*) aux; + __v4sf *v_out = ( __v4sf*) out; - const __v4sf one = _mm_set1_ps (1.0f); + const __v4sf one = _mm_set1_ps (1.0f); const __v4sf v_opacity = _mm_set1_ps (opacity); - while (samples--) + switch (layer_mode->composite_mode) { - __v4sf rgba_in, rgba_aux, alpha; - - rgba_in = *v_in++; - rgba_aux = *v_aux++; - - /* expand alpha */ - alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_aux, - _MM_SHUFFLE (3, 3, 3, 3)); - - if (mask) + case GIMP_LAYER_COMPOSITE_SRC_OVER: + case GIMP_LAYER_COMPOSITE_AUTO: + while (samples--) { - __v4sf mask_alpha; + __v4sf rgba_in, rgba_aux, alpha; - /* multiply aux's alpha by the mask */ - mask_alpha = _mm_set1_ps (*mask++); - alpha = alpha * mask_alpha; - } - - alpha = alpha * v_opacity; - - if (_mm_ucomigt_ss (alpha, _mm_setzero_ps ())) - { - __v4sf dst_alpha, a_term, out_pixel, out_alpha, out_pixel_rbaa; + rgba_in = *v_in++; + rgba_aux = *v_aux++; /* expand alpha */ - dst_alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_in, - _MM_SHUFFLE (3, 3, 3, 3)); + alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_aux, + _MM_SHUFFLE (3, 3, 3, 3)); - /* a_term = dst_a * (1.0 - src_a) */ - a_term = dst_alpha * (one - alpha); + if (mask) + { + __v4sf mask_alpha; - /* out(color) = src * src_a + dst * a_term */ - out_pixel = rgba_aux * alpha + rgba_in * a_term; + /* multiply aux's alpha by the mask */ + mask_alpha = _mm_set1_ps (*mask++); + alpha = alpha * mask_alpha; + } - /* out(alpha) = 1.0 * src_a + 1.0 * a_term */ - out_alpha = alpha + a_term; + alpha = alpha * v_opacity; - /* un-premultiply */ - out_pixel = out_pixel / out_alpha; + if (_mm_ucomigt_ss (alpha, _mm_setzero_ps ())) + { + __v4sf dst_alpha, a_term, out_pixel, out_alpha, out_pixel_rbaa; + + /* expand alpha */ + dst_alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_in, + _MM_SHUFFLE (3, 3, 3, 3)); + + /* a_term = dst_a * (1.0 - src_a) */ + a_term = dst_alpha * (one - alpha); + + /* out(color) = src * src_a + dst * a_term */ + out_pixel = rgba_aux * alpha + rgba_in * a_term; + + /* out(alpha) = 1.0 * src_a + 1.0 * a_term */ + out_alpha = alpha + a_term; + + /* un-premultiply */ + out_pixel = out_pixel / out_alpha; + + /* swap in the real alpha */ + out_pixel_rbaa = _mm_shuffle_ps (out_pixel, out_alpha, _MM_SHUFFLE (3, 3, 2, 0)); + out_pixel = _mm_shuffle_ps (out_pixel, out_pixel_rbaa, _MM_SHUFFLE (2, 1, 1, 0)); + + *v_out++ = out_pixel; + } + else + { + *v_out++ = rgba_in; + } + } + break; + + case GIMP_LAYER_COMPOSITE_SRC_ATOP: + while (samples--) + { + __v4sf rgba_in, rgba_aux, alpha; + + rgba_in = *v_in++; + rgba_aux = *v_aux++; + + /* expand alpha */ + alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_aux, + _MM_SHUFFLE (3, 3, 3, 3)); + + if (mask) + { + __v4sf mask_alpha; + + /* multiply aux's alpha by the mask */ + mask_alpha = _mm_set1_ps (*mask++); + alpha = alpha * mask_alpha; + } + + alpha = alpha * v_opacity; + + if (_mm_ucomigt_ss (alpha, _mm_setzero_ps ())) + { + __v4sf dst_alpha, out_pixel, out_pixel_rbaa; + + /* expand alpha */ + dst_alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_in, + _MM_SHUFFLE (3, 3, 3, 3)); + + /* out(color) = dst * (1 - src_a) + src * src_a */ + out_pixel = rgba_in + (rgba_aux - rgba_in) * alpha; + + /* swap in the real alpha */ + out_pixel_rbaa = _mm_shuffle_ps (out_pixel, dst_alpha, _MM_SHUFFLE (3, 3, 2, 0)); + out_pixel = _mm_shuffle_ps (out_pixel, out_pixel_rbaa, _MM_SHUFFLE (2, 1, 1, 0)); + + *v_out++ = out_pixel; + } + else + { + *v_out++ = rgba_in; + } + } + break; + + case GIMP_LAYER_COMPOSITE_DST_ATOP: + while (samples--) + { + __v4sf rgba_in, rgba_aux, alpha; + __v4sf out_pixel, out_pixel_rbaa; + + rgba_in = *v_in++; + rgba_aux = *v_aux++; + + /* expand alpha */ + alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_aux, + _MM_SHUFFLE (3, 3, 3, 3)); + + if (mask) + { + __v4sf mask_alpha; + + /* multiply aux's alpha by the mask */ + mask_alpha = _mm_set1_ps (*mask++); + alpha = alpha * mask_alpha; + } + + alpha = alpha * v_opacity; + + if (_mm_ucomigt_ss (alpha, _mm_setzero_ps ())) + { + /* out(color) = src */ + out_pixel = rgba_aux; + } + else + { + out_pixel = rgba_in; + } /* swap in the real alpha */ - out_pixel_rbaa = _mm_shuffle_ps (out_pixel, out_alpha, _MM_SHUFFLE (3, 3, 2, 0)); + out_pixel_rbaa = _mm_shuffle_ps (out_pixel, alpha, _MM_SHUFFLE (3, 3, 2, 0)); out_pixel = _mm_shuffle_ps (out_pixel, out_pixel_rbaa, _MM_SHUFFLE (2, 1, 1, 0)); *v_out++ = out_pixel; } - else + break; + + case GIMP_LAYER_COMPOSITE_SRC_IN: + while (samples--) { - *v_out++ = rgba_in; + __v4sf rgba_in, rgba_aux, alpha; + __v4sf out_pixel, out_pixel_rbaa; + + rgba_in = *v_in++; + rgba_aux = *v_aux++; + + /* expand alpha */ + alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_aux, + _MM_SHUFFLE (3, 3, 3, 3)); + + if (mask) + { + __v4sf mask_alpha; + + /* multiply aux's alpha by the mask */ + mask_alpha = _mm_set1_ps (*mask++); + alpha = alpha * mask_alpha; + } + + alpha = alpha * v_opacity; + + /* multiply the alpha by in's alpha */ + alpha *= (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_in, + _MM_SHUFFLE (3, 3, 3, 3)); + + if (_mm_ucomigt_ss (alpha, _mm_setzero_ps ())) + { + /* out(color) = src */ + out_pixel = rgba_aux; + } + else + { + out_pixel = rgba_in; + } + + /* swap in the real alpha */ + out_pixel_rbaa = _mm_shuffle_ps (out_pixel, alpha, _MM_SHUFFLE (3, 3, 2, 0)); + out_pixel = _mm_shuffle_ps (out_pixel, out_pixel_rbaa, _MM_SHUFFLE (2, 1, 1, 0)); + + *v_out++ = out_pixel; } + break; } } diff --git a/app/operations/layer-modes/gimpoperationnormal-sse4.c b/app/operations/layer-modes/gimpoperationnormal-sse4.c index 1e91c064a4..72825cf5a3 100644 --- a/app/operations/layer-modes/gimpoperationnormal-sse4.c +++ b/app/operations/layer-modes/gimpoperationnormal-sse4.c @@ -52,66 +52,205 @@ gimp_operation_normal_process_sse4 (GeglOperation *operation, } else { - gfloat opacity = ((GimpOperationLayerMode *)(operation))->opacity; - gfloat *mask = mask_p; - const __v4sf *v_in = (const __v4sf*) in; - const __v4sf *v_aux = (const __v4sf*) aux; - __v4sf *v_out = ( __v4sf*) out; + GimpOperationLayerMode *layer_mode = (GimpOperationLayerMode *) operation; + gfloat opacity = layer_mode->opacity; + gfloat *mask = mask_p; + const __v4sf *v_in = (const __v4sf*) in; + const __v4sf *v_aux = (const __v4sf*) aux; + __v4sf *v_out = ( __v4sf*) out; - const __v4sf one = _mm_set1_ps (1.0f); + const __v4sf one = _mm_set1_ps (1.0f); const __v4sf v_opacity = _mm_set1_ps (opacity); - while (samples--) + switch (layer_mode->composite_mode) { - __v4sf rgba_in, rgba_aux, alpha; - - rgba_in = *v_in++; - rgba_aux = *v_aux++; - - /* expand alpha */ - alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_aux, - _MM_SHUFFLE (3, 3, 3, 3)); - - if (mask) + case GIMP_LAYER_COMPOSITE_SRC_OVER: + case GIMP_LAYER_COMPOSITE_AUTO: + while (samples--) { - __v4sf mask_alpha; + __v4sf rgba_in, rgba_aux, alpha; - /* multiply aux's alpha by the mask */ - mask_alpha = _mm_set1_ps (*mask++); - alpha = alpha * mask_alpha; - } - - alpha = alpha * v_opacity; - - if (_mm_ucomigt_ss (alpha, _mm_setzero_ps ())) - { - __v4sf dst_alpha, a_term, out_pixel, out_alpha; + rgba_in = *v_in++; + rgba_aux = *v_aux++; /* expand alpha */ - dst_alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_in, - _MM_SHUFFLE (3, 3, 3, 3)); + alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_aux, + _MM_SHUFFLE (3, 3, 3, 3)); - /* a_term = dst_a * (1.0 - src_a) */ - a_term = dst_alpha * (one - alpha); + if (mask) + { + __v4sf mask_alpha; - /* out(color) = src * src_a + dst * a_term */ - out_pixel = rgba_aux * alpha + rgba_in * a_term; + /* multiply aux's alpha by the mask */ + mask_alpha = _mm_set1_ps (*mask++); + alpha = alpha * mask_alpha; + } - /* out(alpha) = 1.0 * src_a + 1.0 * a_term */ - out_alpha = alpha + a_term; + alpha = alpha * v_opacity; - /* un-premultiply */ - out_pixel = out_pixel / out_alpha; + if (_mm_ucomigt_ss (alpha, _mm_setzero_ps ())) + { + __v4sf dst_alpha, a_term, out_pixel, out_alpha; + + /* expand alpha */ + dst_alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_in, + _MM_SHUFFLE (3, 3, 3, 3)); + + /* a_term = dst_a * (1.0 - src_a) */ + a_term = dst_alpha * (one - alpha); + + /* out(color) = src * src_a + dst * a_term */ + out_pixel = rgba_aux * alpha + rgba_in * a_term; + + /* out(alpha) = 1.0 * src_a + 1.0 * a_term */ + out_alpha = alpha + a_term; + + /* un-premultiply */ + out_pixel = out_pixel / out_alpha; + + /* swap in the real alpha */ + out_pixel = _mm_blend_ps (out_pixel, out_alpha, 0x08); + + *v_out++ = out_pixel; + } + else + { + *v_out++ = rgba_in; + } + } + break; + + case GIMP_LAYER_COMPOSITE_SRC_ATOP: + while (samples--) + { + __v4sf rgba_in, rgba_aux, alpha; + + rgba_in = *v_in++; + rgba_aux = *v_aux++; + + /* expand alpha */ + alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_aux, + _MM_SHUFFLE (3, 3, 3, 3)); + + if (mask) + { + __v4sf mask_alpha; + + /* multiply aux's alpha by the mask */ + mask_alpha = _mm_set1_ps (*mask++); + alpha = alpha * mask_alpha; + } + + alpha = alpha * v_opacity; + + if (_mm_ucomigt_ss (alpha, _mm_setzero_ps ())) + { + __v4sf dst_alpha, out_pixel; + + /* expand alpha */ + dst_alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_in, + _MM_SHUFFLE (3, 3, 3, 3)); + + /* out(color) = dst * (1 - src_a) + src * src_a */ + out_pixel = rgba_in + (rgba_aux - rgba_in) * alpha; + + /* swap in the real alpha */ + out_pixel = _mm_blend_ps (out_pixel, dst_alpha, 0x08); + + *v_out++ = out_pixel; + } + else + { + *v_out++ = rgba_in; + } + } + break; + + case GIMP_LAYER_COMPOSITE_DST_ATOP: + while (samples--) + { + __v4sf rgba_in, rgba_aux, alpha; + __v4sf out_pixel; + + rgba_in = *v_in++; + rgba_aux = *v_aux++; + + /* expand alpha */ + alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_aux, + _MM_SHUFFLE (3, 3, 3, 3)); + + if (mask) + { + __v4sf mask_alpha; + + /* multiply aux's alpha by the mask */ + mask_alpha = _mm_set1_ps (*mask++); + alpha = alpha * mask_alpha; + } + + alpha = alpha * v_opacity; + + if (_mm_ucomigt_ss (alpha, _mm_setzero_ps ())) + { + /* out(color) = src */ + out_pixel = rgba_aux; + } + else + { + out_pixel = rgba_in; + } /* swap in the real alpha */ - out_pixel = _mm_blend_ps (out_pixel, out_alpha, 0x08); + out_pixel = _mm_blend_ps (out_pixel, alpha, 0x08); *v_out++ = out_pixel; } - else + break; + + case GIMP_LAYER_COMPOSITE_SRC_IN: + while (samples--) { - *v_out++ = rgba_in; + __v4sf rgba_in, rgba_aux, alpha; + __v4sf out_pixel; + + rgba_in = *v_in++; + rgba_aux = *v_aux++; + + /* expand alpha */ + alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_aux, + _MM_SHUFFLE (3, 3, 3, 3)); + + if (mask) + { + __v4sf mask_alpha; + + /* multiply aux's alpha by the mask */ + mask_alpha = _mm_set1_ps (*mask++); + alpha = alpha * mask_alpha; + } + + alpha = alpha * v_opacity; + + /* multiply the alpha by in's alpha */ + alpha *= (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_in, + _MM_SHUFFLE (3, 3, 3, 3)); + + if (_mm_ucomigt_ss (alpha, _mm_setzero_ps ())) + { + /* out(color) = src */ + out_pixel = rgba_aux; + } + else + { + out_pixel = rgba_in; + } + + /* swap in the real alpha */ + out_pixel = _mm_blend_ps (out_pixel, alpha, 0x08); + + *v_out++ = out_pixel; } + break; } } diff --git a/app/operations/layer-modes/gimpoperationnormal.c b/app/operations/layer-modes/gimpoperationnormal.c index 2e4d5fb1c6..30870a782b 100644 --- a/app/operations/layer-modes/gimpoperationnormal.c +++ b/app/operations/layer-modes/gimpoperationnormal.c @@ -123,43 +123,166 @@ gimp_operation_normal_process_core (GeglOperation *op, gfloat opacity = layer_mode->opacity; const gboolean has_mask = mask != NULL; - while (samples--) + switch (layer_mode->composite_mode) { - gfloat layer_alpha; - - layer_alpha = layer[ALPHA] * opacity; - if (has_mask) - layer_alpha *= *mask; - - out[ALPHA] = layer_alpha + in[ALPHA] - layer_alpha * in[ALPHA]; - - if (out[ALPHA]) + case GIMP_LAYER_COMPOSITE_SRC_OVER: + case GIMP_LAYER_COMPOSITE_AUTO: + while (samples--) { - gfloat layer_weight = layer_alpha / out[ALPHA]; - gfloat in_weight = 1.0f - layer_weight; - gint b; + gfloat layer_alpha; - for (b = RED; b < ALPHA; b++) + layer_alpha = layer[ALPHA] * opacity; + if (has_mask) + layer_alpha *= *mask; + + out[ALPHA] = layer_alpha + in[ALPHA] - layer_alpha * in[ALPHA]; + + if (out[ALPHA]) { - out[b] = layer[b] * layer_weight + in[b] * in_weight; + gfloat layer_weight = layer_alpha / out[ALPHA]; + gfloat in_weight = 1.0f - layer_weight; + gint b; + + for (b = RED; b < ALPHA; b++) + { + out[b] = layer[b] * layer_weight + in[b] * in_weight; + } } + else + { + gint b; + + for (b = RED; b < ALPHA; b++) + { + out[b] = in[b]; + } + } + + in += 4; + layer += 4; + out += 4; + + if (has_mask) + mask++; } - else + break; + + case GIMP_LAYER_COMPOSITE_SRC_ATOP: + while (samples--) { - gint b; + gfloat layer_alpha; - for (b = RED; b < ALPHA; b++) + layer_alpha = layer[ALPHA] * opacity; + if (has_mask) + layer_alpha *= *mask; + + out[ALPHA] = in[ALPHA]; + + if (out[ALPHA]) { - out[b] = in[b]; + gint b; + + for (b = RED; b < ALPHA; b++) + { + out[b] = in[b] + (layer[b] - in[b]) * layer_alpha; + } } + else + { + gint b; + + for (b = RED; b < ALPHA; b++) + { + out[b] = in[b]; + } + } + + in += 4; + layer += 4; + out += 4; + + if (has_mask) + mask++; } + break; - in += 4; - layer += 4; - out += 4; + case GIMP_LAYER_COMPOSITE_DST_ATOP: + while (samples--) + { + gfloat layer_alpha; - if (has_mask) - mask++; + layer_alpha = layer[ALPHA] * opacity; + if (has_mask) + layer_alpha *= *mask; + + out[ALPHA] = layer_alpha; + + if (out[ALPHA]) + { + gint b; + + for (b = RED; b < ALPHA; b++) + { + out[b] = layer[b]; + } + } + else + { + gint b; + + for (b = RED; b < ALPHA; b++) + { + out[b] = in[b]; + } + } + + in += 4; + layer += 4; + out += 4; + + if (has_mask) + mask++; + } + break; + + case GIMP_LAYER_COMPOSITE_SRC_IN: + while (samples--) + { + gfloat layer_alpha; + + layer_alpha = layer[ALPHA] * opacity; + if (has_mask) + layer_alpha *= *mask; + + out[ALPHA] = in[ALPHA] * layer_alpha; + + if (out[ALPHA]) + { + gint b; + + for (b = RED; b < ALPHA; b++) + { + out[b] = layer[b]; + } + } + else + { + gint b; + + for (b = RED; b < ALPHA; b++) + { + out[b] = in[b]; + } + } + + in += 4; + layer += 4; + out += 4; + + if (has_mask) + mask++; + } + break; } return TRUE;