33#define DT_BLENDIF_RGB_CH 4
34#define DT_BLENDIF_RGB_BCH 3
38 float *
const restrict
out,
const float *
const restrict mask,
const size_t stride);
43 const
float *const restrict parameters)
46 if(
value <= parameters[0])
51 else if(
value < parameters[1])
56 else if(
value <= parameters[2])
61 else if(
value < parameters[3])
64 factor = 1.0f - (
value - parameters[2]) * parameters[5];
75static inline
void _blendif_gray(const float *const restrict pixels, float *const restrict mask,
76 const size_t stride, const float *const restrict parameters,
77 const unsigned int invert_mask,
82 const float value = dt_ioppr_get_rgb_matrix_luminance(pixels + j, profile->matrix_in, profile->lut_in,
83 profile->unbounded_coeffs_in, profile->lutsize,
84 profile->nonlinearlut);
90static inline
void _blendif_rgb_red(const float *const restrict pixels, float *const restrict mask,
91 const size_t stride, const float *const restrict parameters,
92 const unsigned int invert_mask)
101static inline
void _blendif_rgb_green(const float *const restrict pixels, float *const restrict
mask,
102 const size_t stride, const float *const restrict parameters,
103 const unsigned int invert_mask)
112static inline
void _blendif_rgb_blue(const float *const restrict pixels, float *const restrict
mask,
113 const size_t stride, const float *const restrict parameters,
114 const unsigned int invert_mask)
123static inline
void _blendif_jzczhz(const float *const restrict pixels, float *const restrict mask,
124 const size_t stride, const float *const restrict parameters,
125 const unsigned int *const restrict invert_mask,
136 dt_ioppr_rgb_matrix_to_xyz(pixels + j,
XYZ_D65, profile->matrix_out_transposed, profile->lut_in,
137 profile->unbounded_coeffs_in, profile->lutsize, profile->nonlinearlut);
140 dt_JzAzBz_2_JzCzhz(
JzAzBz, JzCzhz);
143 for(
size_t i = 0;
i < 3;
i++)
151static
void _blendif_combine_channels(const float *const restrict pixels, float *const restrict mask,
152 const size_t stride, const unsigned int blendif,
153 const float *const restrict parameters,
160 invert_mask, profile);
173 _blendif_rgb_green(pixels, mask, stride,
192 invert_mask, profile);
198 const float *
const restrict a,
199 const float *
const restrict b,
float *
const restrict mask)
207 const int xoffs = roi_out->
x - roi_in->
x;
208 const int yoffs = roi_out->
y - roi_in->
y;
209 const int iwidth = roi_in->
width;
210 const int owidth = roi_out->
width;
211 const int oheight = roi_out->
height;
223 const size_t buffsize = (size_t)owidth * oheight;
226 const float global_opacity =
clamp_simd(
d->opacity / 100.0f);
234 for(
size_t x = 0;
x < buffsize;
x++) mask[
x] = global_opacity * (1.0f - mask[
x]);
241 else if(canceling_channel || !any_channel_active)
246 const float opac = ((mask_inversed == 0) ^ (mask_inclusive == 0)) ? global_opacity : 0.0f;
274 for(
size_t x = 0;
x < buffsize;
x++) temp_mask[
x] = 1.0f;
278 for(
size_t y = 0; y < oheight; y++)
281 _blendif_combine_channels(a + start, temp_mask + (y * owidth), owidth, blendif, parameters, profile);
284 for(
size_t y = 0; y < oheight; y++)
298 for(
size_t x = 0;
x < buffsize;
x++) mask[
x] = global_opacity * (1.0f - mask[
x]) * temp_mask[
x];
303 for(
size_t x = 0;
x < buffsize;
x++) mask[
x] = global_opacity * (1.0f - (1.0f - mask[
x]) * temp_mask[
x]);
311 for(
size_t x = 0;
x < buffsize;
x++) mask[
x] = global_opacity * (1.0f - mask[
x] * temp_mask[
x]);
316 for(
size_t x = 0;
x < buffsize;
x++) mask[
x] = global_opacity * mask[
x] * temp_mask[
x];
328static
void _blend_normal(const float *const restrict a, const float *const restrict b, const float
p,
329 float *const restrict
out, const float *const restrict mask, const size_t stride)
333 const float local_opacity = mask[
i];
336 out[j +
k] = a[j +
k] * (1.0f - local_opacity) + b[j +
k] * local_opacity;
344static
void _blend_multiply(const float *const restrict
a, const float *const restrict
b, const float
p,
345 float *const restrict
out, const float *const restrict
mask, const size_t stride)
349 const float local_opacity =
mask[
i];
352 out[j +
k] =
a[j +
k] * (1.0f - local_opacity) + (a[j +
k] * b[j +
k] *
p) * local_opacity;
360static
void _blend_add(const float *const restrict
a, const float *const restrict
b, const float
p,
361 float *const restrict
out, const float *const restrict
mask, const size_t stride)
365 const float local_opacity =
mask[
i];
368 out[j +
k] =
a[j +
k] * (1.0f - local_opacity) + (a[j +
k] +
p * b[j +
k]) * local_opacity;
376static
void _blend_subtract(const float *const restrict
a, const float *const restrict
b, const float
p,
377 float *const restrict
out, const float *const restrict
mask, const size_t stride)
381 const float local_opacity =
mask[
i];
384 out[j +
k] =
a[j +
k] * (1.0f - local_opacity) + fmaxf(a[j +
k] -
p * b[j +
k], 0.0f) * local_opacity;
386 out[j + 3] = local_opacity;
392static
void _blend_subtract_inverse(const float *const restrict
a, const float *const restrict
b, const float
p,
393 float *const restrict
out, const float *const restrict
mask,
398 const float local_opacity =
mask[
i];
401 out[j +
k] =
a[j +
k] * (1.0f - local_opacity) + fmaxf(b[j +
k] -
p * a[j +
k], 0.0f) * local_opacity;
403 out[j + 3] = local_opacity;
409static
void _blend_difference(const float *const restrict
a, const float *const restrict
b, const float
p,
410 float *const restrict
out, const float *const restrict
mask, const size_t stride)
414 const float local_opacity =
mask[
i];
417 out[j +
k] =
a[j +
k] * (1.0f - local_opacity) + fabsf(a[j +
k] - b[j +
k]) * local_opacity;
425static
void _blend_divide(const float *const restrict
a, const float *const restrict
b, const float
p,
426 float *const restrict
out, const float *const restrict
mask, const size_t stride)
430 const float local_opacity =
mask[
i];
433 out[j +
k] =
a[j +
k] * (1.0f - local_opacity) + a[j +
k] / fmaxf(
p * b[j +
k], 1e-6f) * local_opacity;
441static
void _blend_divide_inverse(const float *const restrict
a, const float *const restrict
b, const float
p,
442 float *const restrict
out, const float *const restrict
mask, const size_t stride)
446 const float local_opacity =
mask[
i];
449 out[j +
k] =
a[j +
k] * (1.0f - local_opacity) + b[j +
k] / fmaxf(
p * a[j +
k], 1e-6f) * local_opacity;
457static
void _blend_average(const float *const restrict
a, const float *const restrict
b, const float
p,
458 float *const restrict
out, const float *const restrict
mask, const size_t stride)
462 const float local_opacity =
mask[
i];
465 out[j +
k] =
a[j +
k] * (1.0f - local_opacity) + (a[j +
k] + b[j +
k]) / 2.0f * local_opacity;
473static
void _blend_geometric_mean(const float *const restrict
a, const float *const restrict
b, const float
p,
474 float *const restrict
out, const float *const restrict
mask, const size_t stride)
478 const float local_opacity =
mask[
i];
481 out[j +
k] =
a[j +
k] * (1.0f - local_opacity) + sqrtf(fmax(a[j +
k] * b[j +
k], 0.0f)) * local_opacity;
489static
void _blend_harmonic_mean(const float *const restrict
a, const float *const restrict
b, const float
p,
490 float *const restrict
out, const float *const restrict
mask, const size_t stride)
494 const float local_opacity =
mask[
i];
498 out[j +
k] =
a[j +
k] * (1.0f - local_opacity)
499 + 2.0f * a[j +
k] * b[j +
k] / (fmaxf(a[j +
k], 5e-7f) + fmaxf(b[j +
k], 5e-7f)) * local_opacity;
507static
void _blend_chromaticity(const float *const restrict
a, const float *const restrict
b, const float
p,
508 float *const restrict
out, const float *const restrict
mask, const size_t stride)
512 const float local_opacity =
mask[
i];
513 const float norm_a = fmax(sqrtf(sqf(a[j]) + sqf(a[j + 1]) + sqf(a[j + 2])), 1e-6f);
514 const float norm_b = fmax(sqrtf(sqf(b[j]) + sqf(b[j + 1]) + sqf(b[j + 2])), 1e-6f);
517 out[j +
k] =
a[j +
k] * (1.0f - local_opacity) + b[j +
k] * norm_a / norm_b * local_opacity;
525static
void _blend_luminance(const float *const restrict
a, const float *const restrict
b, const float
p,
526 float *const restrict
out, const float *const restrict
mask, const size_t stride)
530 const float local_opacity =
mask[
i];
531 const float norm_a = fmax(sqrtf(sqf(a[j]) + sqf(a[j + 1]) + sqf(a[j + 2])), 1e-6f);
532 const float norm_b = fmax(sqrtf(sqf(b[j]) + sqf(b[j + 1]) + sqf(b[j + 2])), 1e-6f);
535 out[j +
k] =
a[j +
k] * (1.0f - local_opacity) + a[j +
k] * norm_b / norm_a * local_opacity;
543static
void _blend_RGB_R(const float *const restrict
a, const float *const restrict
b, const float
p,
544 float *const restrict
out, const float *const restrict
mask, const size_t stride)
548 const float local_opacity =
mask[
i];
549 out[j + 0] =
a[j + 0] * (1.0f - local_opacity) +
p * b[j + 0] * local_opacity;
550 out[j + 1] =
a[j + 1];
551 out[j + 2] =
a[j + 2];
552 out[j + 3] = local_opacity;
558static
void _blend_RGB_G(const float *const restrict
a, const float *const restrict
b, const float
p,
559 float *const restrict
out, const float *const restrict
mask, const size_t stride)
563 const float local_opacity =
mask[
i];
564 out[j + 0] =
a[j + 0];
565 out[j + 1] =
a[j + 1] * (1.0f - local_opacity) +
p * b[j + 1] * local_opacity;
566 out[j + 2] =
a[j + 2];
567 out[j + 3] = local_opacity;
573static
void _blend_RGB_B(const float *const restrict
a, const float *const restrict
b, const float
p,
574 float *const restrict
out, const float *const restrict
mask, const size_t stride)
578 const float local_opacity =
mask[
i];
579 out[j + 0] =
a[j + 0];
580 out[j + 1] =
a[j + 1];
581 out[j + 2] =
a[j + 2] * (1.0f - local_opacity) +
p * b[j + 2] * local_opacity;
582 out[j + 3] = local_opacity;
595 blend = _blend_multiply;
598 blend = _blend_average;
604 blend = _blend_subtract;
607 blend = _blend_subtract_inverse;
611 blend = _blend_difference;
614 blend = _blend_divide;
617 blend = _blend_divide_inverse;
620 blend = _blend_luminance;
623 blend = _blend_chromaticity;
626 blend = _blend_RGB_R;
629 blend = _blend_RGB_G;
632 blend = _blend_RGB_B;
635 blend = _blend_geometric_mean;
638 blend = _blend_harmonic_mean;
643 blend = _blend_normal;
652static inline float _rgb_luminance(const float *const restrict
rgb,
657 value = dt_ioppr_get_rgb_matrix_luminance(
rgb, profile->matrix_in, profile->lut_in,
658 profile->unbounded_coeffs_in, profile->lutsize,
659 profile->nonlinearlut);
676 dt_ioppr_rgb_matrix_to_xyz(
rgb,
XYZ_D65, profile->matrix_out_transposed, profile->lut_in, profile->unbounded_coeffs_in,
677 profile->lutsize, profile->nonlinearlut);
686 dt_JzAzBz_2_JzCzhz(
JzAzBz, JzCzhz);
691static
void _display_channel(const float *const restrict a, float *const restrict b,
692 const float *const restrict mask, const size_t stride, const int channel,
693 const float *const restrict boost_factors,
792 _rgb_to_JzCzhz(a + j, JzCzhz, profile);
805 _rgb_to_JzCzhz(b + j, JzCzhz, profile);
818 _rgb_to_JzCzhz(a + j, JzCzhz, profile);
831 _rgb_to_JzCzhz(b + j, JzCzhz, profile);
843 _rgb_to_JzCzhz(a + j, JzCzhz, profile);
854 _rgb_to_JzCzhz(b + j, JzCzhz, profile);
872static inline
void _copy_mask(const float *const restrict a, float *const restrict b, const size_t stride)
880 const float *
const restrict a,
float *
const restrict b,
881 const float *
const restrict mask,
890 const int xoffs = roi_out->
x - roi_in->
x;
891 const int yoffs = roi_out->
y - roi_in->
y;
892 const int iwidth = roi_in->
width;
893 const int owidth = roi_out->
width;
894 const int oheight = roi_out->
height;
906 const float *
const restrict boost_factors =
d->blendif_boost_factors;
909 for(
size_t y = 0; y < oheight; y++)
913 const size_t m_start = y * owidth;
914 _display_channel(a + a_start, b + b_start, mask + m_start, owidth, channel, boost_factors, profile);
919 const float p = exp2f(
d->blend_parameter);
929 for(
size_t y = 0; y < oheight; y++)
933 const size_t m_start = y * owidth;
934 blend(tmp_buffer + b_start, a + a_start,
p, b + b_start, mask + m_start, owidth);
940 for(
size_t y = 0; y < oheight; y++)
944 const size_t m_start = y * owidth;
945 blend(a + a_start, tmp_buffer + b_start,
p, b + b_start, mask + m_start, owidth);
956 for(
size_t y = 0; y < oheight; y++)
959 const size_t b_start = y * stride;
960 _copy_mask(a + a_start, b + b_start, stride);
void dt_develop_blendif_process_parameters(float *const restrict parameters, const dt_develop_blend_params_t *const params)
int dt_develop_blendif_init_masking_profile(const struct dt_dev_pixelpipe_t *pipe, const struct dt_dev_pixelpipe_iop_t *piece, dt_iop_order_iccprofile_info_t *blending_profile, dt_develop_blend_colorspace_t cst)
@ DEVELOP_BLEND_CS_RGB_SCENE
@ DEVELOP_BLENDIF_GRAY_out
@ DEVELOP_BLENDIF_GREEN_in
@ DEVELOP_BLENDIF_RED_out
@ DEVELOP_BLENDIF_BLUE_in
@ DEVELOP_BLENDIF_BLUE_out
@ DEVELOP_BLENDIF_RGB_MASK
@ DEVELOP_BLENDIF_GRAY_in
@ DEVELOP_BLENDIF_GREEN_out
#define DEVELOP_BLENDIF_PARAMETER_ITEMS
@ DEVELOP_BLEND_CHROMATICITY
@ DEVELOP_BLEND_DIFFERENCE
@ DEVELOP_BLEND_LIGHTNESS
@ DEVELOP_BLEND_MODE_MASK
@ DEVELOP_BLEND_DIVIDE_INVERSE
@ DEVELOP_BLEND_HARMONIC_MEAN
@ DEVELOP_BLEND_GEOMETRIC_MEAN
@ DEVELOP_BLEND_DIFFERENCE2
@ DEVELOP_BLEND_SUBTRACT_INVERSE
@ DEVELOP_MASK_PARAMETRIC
static _blend_row_func * _choose_blend_func(const unsigned int blend_mode)
static float _blendif_compute_factor(const float value, const unsigned int invert_mask, const float *const restrict parameters)
void dt_develop_blendif_rgb_jzczhz_blend(const struct dt_dev_pixelpipe_t *pipe, const struct dt_dev_pixelpipe_iop_t *piece, const float *const restrict a, float *const restrict b, const float *const restrict mask, const dt_dev_pixelpipe_display_mask_t request_mask_display)
void dt_develop_blendif_rgb_jzczhz_make_mask(const struct dt_dev_pixelpipe_t *pipe, const struct dt_dev_pixelpipe_iop_t *piece, const float *const restrict a, const float *const restrict b, float *const restrict mask)
void() _blend_row_func(const float *const restrict a, const float *const restrict b, const float p, float *const restrict out, const float *const restrict mask, const size_t stride)
#define DT_BLENDIF_RGB_BCH
#define DT_BLENDIF_RGB_CH
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
static dt_aligned_pixel_t rgb
static dt_aligned_pixel_t XYZ_D65
const dt_colormatrix_t dt_aligned_pixel_t out
static dt_aligned_pixel_t JzAzBz
dt_dev_pixelpipe_display_mask_t
@ DT_DEV_PIXELPIPE_DISPLAY_OUTPUT
@ DT_DEV_PIXELPIPE_DISPLAY_G
@ DT_DEV_PIXELPIPE_DISPLAY_ANY
@ DT_DEV_PIXELPIPE_DISPLAY_JzCzhz_hz
@ DT_DEV_PIXELPIPE_DISPLAY_JzCzhz_Cz
@ DT_DEV_PIXELPIPE_DISPLAY_MASK
@ DT_DEV_PIXELPIPE_DISPLAY_JzCzhz_Jz
@ DT_DEV_PIXELPIPE_DISPLAY_GRAY
@ DT_DEV_PIXELPIPE_DISPLAY_B
@ DT_DEV_PIXELPIPE_DISPLAY_R
__DT_CLONE_TARGETS__ void dt_iop_image_mul_const(float *const buf, const float mul_value, const size_t width, const size_t height, const size_t ch)
__DT_CLONE_TARGETS__ void dt_iop_image_copy(float *const __restrict__ out, const float *const __restrict__ in, const size_t nfloats)
__DT_CLONE_TARGETS__ void dt_iop_image_fill(float *const buf, const float fill_value, const size_t width, const size_t height, const size_t ch)
#define DEVELOP_BLENDIF_SIZE
float *const restrict const size_t k
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
#define DT_ALIGNED_PIXEL
Align a 4-float pixel on 16 bytes, enough for SSE. Same struct-member caveat as DT_ALIGNED_ARRAY,...
#define DT_ALIGNED_ARRAY
Align an object on a cacheline boundary, so AVX2 can load it whole.
#define __OMP_SIMD__(...)
#define __OMP_DECLARE_SIMD__(...)
#define __OMP_PARALLEL__(...)
#define __OMP_PARALLEL_FOR__(...)
#define __OMP_FOR_SIMD__(...)
#define __OMP_PARALLEL_FOR_SIMD__(...)
static float clamp_simd(const float x)
#define dt_pixelpipe_cache_alloc_align_float_cache(pixels, id)
#define dt_pixelpipe_cache_free_align(mem)
DT_ALIGNED_PIXEL float dt_aligned_pixel_t[4]
static const dt_aligned_pixel_simd_t value
dt_iop_buffer_dsc_t dsc_in
A profile reduced to the arithmetic the pixel loop can run: two matrices and six tone-curve LUTs,...
Region of interest passed through the pixelpipe.