Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
blendif_rgb_jzczhz.c
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2020-2021 Harold le Clément de Saint-Marcq.
4 Copyright (C) 2020-2021 Hubert Kowalski.
5 Copyright (C) 2020-2021 Ralf Brown.
6 Copyright (C) 2021 Chris Elston.
7 Copyright (C) 2021 Pascal Obry.
8 Copyright (C) 2022 Martin Bařinka.
9 Copyright (C) 2026 Aurélien PIERRE.
10
11 darktable is free software: you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation, either version 3 of the License, or
14 (at your option) any later version.
15
16 darktable is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with darktable. If not, see <http://www.gnu.org/licenses/>.
23*/
24
27#include "common/imagebuf.h"
28#include "develop/blend.h"
29#include "develop/imageop.h"
30#include "math/openmp_maths.h"
31#include <math.h>
32
33#define DT_BLENDIF_RGB_CH 4
34#define DT_BLENDIF_RGB_BCH 3
35
36
37typedef void(_blend_row_func)(const float *const restrict a, const float *const restrict b, const float p,
38 float *const restrict out, const float *const restrict mask, const size_t stride);
39
40
41__OMP_DECLARE_SIMD__(uniform(parameters, invert_mask))
42static inline float _blendif_compute_factor(const float value, const unsigned int invert_mask,
43 const float *const restrict parameters)
44{
45 float factor = 0.0f;
46 if(value <= parameters[0])
47 {
48 // we are below the keyframe
49 factor = 0.0f;
50 }
51 else if(value < parameters[1])
52 {
53 // we are on the bottom slope of the keyframe
54 factor = (value - parameters[0]) * parameters[4];
55 }
56 else if(value <= parameters[2])
57 {
58 // we are on the ramp - constant part - of the keyframe
59 factor = 1.0f;
60 }
61 else if(value < parameters[3])
62 {
63 // we are on the top slope of the keyframe
64 factor = 1.0f - (value - parameters[2]) * parameters[5];
65 }
66 else
67 {
68 // we are above the keyframe
69 factor = 0.0f;
70 }
71 return invert_mask ? 1.0f - factor : factor; // inverted channel?
72}
73
74__OMP_DECLARE_SIMD__(aligned(pixels: 16) uniform(parameters, invert_mask, stride, profile))
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,
78 const dt_iop_order_iccprofile_info_t *const restrict profile)
79{
80 for(size_t x = 0, j = 0; x < stride; x++, j += DT_BLENDIF_RGB_CH)
81 {
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);
85 mask[x] *= _blendif_compute_factor(value, invert_mask, parameters);
86 }
87}
88
89__OMP_DECLARE_SIMD__(aligned(pixels: 16) uniform(parameters, invert_mask, stride))
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)
93{
94 for(size_t x = 0, j = 0; x < stride; x++, j += DT_BLENDIF_RGB_CH)
95 {
96 mask[x] *= _blendif_compute_factor(pixels[j + 0], invert_mask, parameters);
97 }
98}
99
100__OMP_DECLARE_SIMD__(aligned(pixels: 16) uniform(parameters, invert_mask, stride))
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)
104{
105 for(size_t x = 0, j = 0; x < stride; x++, j += DT_BLENDIF_RGB_CH)
106 {
107 mask[x] *= _blendif_compute_factor(pixels[j + 1], invert_mask, parameters);
108 }
109}
110
111__OMP_DECLARE_SIMD__(aligned(pixels: 16) uniform(parameters, invert_mask, stride))
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)
115{
116 for(size_t x = 0, j = 0; x < stride; x++, j += DT_BLENDIF_RGB_CH)
117 {
118 mask[x] *= _blendif_compute_factor(pixels[j + 2], invert_mask, parameters);
119 }
120}
121
122__OMP_DECLARE_SIMD__(aligned(pixels, invert_mask: 16) uniform(parameters, invert_mask, stride, profile))
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,
126 const dt_iop_order_iccprofile_info_t *const restrict profile)
127{
128 for(size_t x = 0, j = 0; x < stride; x++, j += DT_BLENDIF_RGB_CH)
129 {
132 dt_aligned_pixel_t JzCzhz;
133
134 // use the matrix_out of the hacked profile for blending to use the
135 // conversion from RGB to XYZ D65 (instead of XYZ D50)
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);
138
139 dt_XYZ_2_JzAzBz(XYZ_D65, JzAzBz);
140 dt_JzAzBz_2_JzCzhz(JzAzBz, JzCzhz);
141
142 float factor = 1.0f;
143 for(size_t i = 0; i < 3; i++)
144 factor *= _blendif_compute_factor(JzCzhz[i], invert_mask[i],
145 parameters + DEVELOP_BLENDIF_PARAMETER_ITEMS * i);
146 mask[x] *= factor;
147 }
148}
149
150__OMP_DECLARE_SIMD__(aligned(pixels: 16) uniform(stride, blendif, parameters, profile))
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,
154 const dt_iop_order_iccprofile_info_t *const restrict profile)
155{
156 if(blendif & (1 << DEVELOP_BLENDIF_GRAY_in))
157 {
158 const unsigned int invert_mask = (blendif >> 16) & (1 << DEVELOP_BLENDIF_GRAY_in);
159 _blendif_gray(pixels, mask, stride, parameters + DEVELOP_BLENDIF_PARAMETER_ITEMS * DEVELOP_BLENDIF_GRAY_in,
160 invert_mask, profile);
161 }
162
163 if(blendif & (1 << DEVELOP_BLENDIF_RED_in))
164 {
165 const unsigned int invert_mask = (blendif >> 16) & (1 << DEVELOP_BLENDIF_RED_in);
166 _blendif_rgb_red(pixels, mask, stride, parameters + DEVELOP_BLENDIF_PARAMETER_ITEMS * DEVELOP_BLENDIF_RED_in,
167 invert_mask);
168 }
169
170 if(blendif & (1 << DEVELOP_BLENDIF_GREEN_in))
171 {
172 const unsigned int invert_mask = (blendif >> 16) & (1 << DEVELOP_BLENDIF_GREEN_in);
173 _blendif_rgb_green(pixels, mask, stride,
175 }
176
177 if(blendif & (1 << DEVELOP_BLENDIF_BLUE_in))
178 {
179 const unsigned int invert_mask = (blendif >> 16) & (1 << DEVELOP_BLENDIF_BLUE_in);
180 _blendif_rgb_blue(pixels, mask, stride, parameters + DEVELOP_BLENDIF_PARAMETER_ITEMS * DEVELOP_BLENDIF_BLUE_in,
181 invert_mask);
182 }
183
184 if(blendif & ((1 << DEVELOP_BLENDIF_Jz_in) | (1 << DEVELOP_BLENDIF_Cz_in) | (1 << DEVELOP_BLENDIF_hz_in)))
185 {
186 const unsigned int invert_mask[3] DT_ALIGNED_PIXEL = {
187 (blendif >> 16) & (1 << DEVELOP_BLENDIF_Jz_in),
188 (blendif >> 16) & (1 << DEVELOP_BLENDIF_Cz_in),
189 (blendif >> 16) & (1 << DEVELOP_BLENDIF_hz_in),
190 };
191 _blendif_jzczhz(pixels, mask, stride, parameters + DEVELOP_BLENDIF_PARAMETER_ITEMS * DEVELOP_BLENDIF_Jz_in,
192 invert_mask, profile);
193 }
194}
195
197 const struct dt_dev_pixelpipe_iop_t *piece,
198 const float *const restrict a,
199 const float *const restrict b, float *const restrict mask)
200{
201 const dt_iop_roi_t *const roi_in = &piece->roi_in;
202 const dt_iop_roi_t *const roi_out = &piece->roi_out;
203 const dt_develop_blend_params_t *const d = (const dt_develop_blend_params_t *const)piece->blendop_data;
204
205 if(piece->dsc_in.channels != DT_BLENDIF_RGB_CH) return;
206
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;
212
213 const unsigned int any_channel_active = d->blendif & DEVELOP_BLENDIF_RGB_MASK;
214 const unsigned int mask_inclusive = d->mask_combine & DEVELOP_COMBINE_INCL;
215 const unsigned int mask_inversed = d->mask_combine & DEVELOP_COMBINE_INV;
216
217 // invert the individual channels if the combine mode is inclusive
218 const unsigned int blendif = d->blendif ^ (mask_inclusive ? DEVELOP_BLENDIF_RGB_MASK << 16 : 0);
219
220 // a channel cancels the mask if the whole span is selected and the channel is inverted
221 const unsigned int canceling_channel = (blendif >> 16) & ~blendif & DEVELOP_BLENDIF_RGB_MASK;
222
223 const size_t buffsize = (size_t)owidth * oheight;
224
225 // get the clipped opacity value 0 - 1
226 const float global_opacity = clamp_simd(d->opacity / 100.0f);
227
228 if(!(d->mask_mode & DEVELOP_MASK_PARAMETRIC) || (!canceling_channel && !any_channel_active))
229 {
230 // mask is not conditional, invert the mask if required
231 if(mask_inversed)
232 {
234 for(size_t x = 0; x < buffsize; x++) mask[x] = global_opacity * (1.0f - mask[x]);
235 }
236 else
237 {
238 dt_iop_image_mul_const(mask,global_opacity,owidth,oheight,1); // mask[k] *= global_opacity;
239 }
240 }
241 else if(canceling_channel || !any_channel_active)
242 {
243 // one of the conditional channel selects nothing
244 // this means that the conditional opacity of all pixels is the same
245 // and depends on whether the mask combination is inclusive and whether the mask is inverted
246 const float opac = ((mask_inversed == 0) ^ (mask_inclusive == 0)) ? global_opacity : 0.0f;
247 dt_iop_image_fill(mask,opac,owidth,oheight,1); // mask[k] = opac;
248 }
249 else
250 {
251 // we need to process all conditional channels
252
253 // parameters, for every channel the 4 limits + pre-computed increasing slope and decreasing slope
256
257 dt_iop_order_iccprofile_info_t blend_profile;
259 {
260 return;
261 }
262 const dt_iop_order_iccprofile_info_t *profile = &blend_profile;
263
264 // allocate space for a temporary mask buffer to split the computation of every channel
265 float *const restrict temp_mask = dt_pixelpipe_cache_alloc_align_float_cache(buffsize, 0);
266 if(IS_NULL_PTR(temp_mask))
267 {
268 return;
269 }
271 {
272 // initialize the parametric mask
273 __OMP_FOR_SIMD__(aligned(temp_mask:64))
274 for(size_t x = 0; x < buffsize; x++) temp_mask[x] = 1.0f;
275
276 // combine channels
278 for(size_t y = 0; y < oheight; y++)
279 {
280 const size_t start = ((y + yoffs) * iwidth + xoffs) * DT_BLENDIF_RGB_CH;
281 _blendif_combine_channels(a + start, temp_mask + (y * owidth), owidth, blendif, parameters, profile);
282 }
284 for(size_t y = 0; y < oheight; y++)
285 {
286 const size_t start = (y * owidth) * DT_BLENDIF_RGB_CH;
287 _blendif_combine_channels(b + start, temp_mask + (y * owidth), owidth, blendif >> DEVELOP_BLENDIF_GRAY_out,
289 profile);
290 }
291
292 // apply global opacity
293 if(mask_inclusive)
294 {
295 if(mask_inversed)
296 {
297 __OMP_FOR_SIMD__(aligned(mask, temp_mask:64))
298 for(size_t x = 0; x < buffsize; x++) mask[x] = global_opacity * (1.0f - mask[x]) * temp_mask[x];
299 }
300 else
301 {
302 __OMP_FOR_SIMD__(aligned(mask, temp_mask:64))
303 for(size_t x = 0; x < buffsize; x++) mask[x] = global_opacity * (1.0f - (1.0f - mask[x]) * temp_mask[x]);
304 }
305 }
306 else
307 {
308 if(mask_inversed)
309 {
310 __OMP_FOR_SIMD__(aligned(mask, temp_mask:64))
311 for(size_t x = 0; x < buffsize; x++) mask[x] = global_opacity * (1.0f - mask[x] * temp_mask[x]);
312 }
313 else
314 {
315 __OMP_FOR_SIMD__(aligned(mask, temp_mask:64))
316 for(size_t x = 0; x < buffsize; x++) mask[x] = global_opacity * mask[x] * temp_mask[x];
317 }
318 }
319 }
320
322 }
323}
324
325
326/* normal blend without any clamping */
327__OMP_DECLARE_SIMD__(aligned(a, b, out:16) uniform(p, stride))
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)
330{
331 for(size_t i = 0, j = 0; i < stride; i++, j += DT_BLENDIF_RGB_CH)
332 {
333 const float local_opacity = mask[i];
334 for(int k = 0; k < DT_BLENDIF_RGB_BCH; k++)
335 {
336 out[j + k] = a[j + k] * (1.0f - local_opacity) + b[j + k] * local_opacity;
337 }
338 out[j + DT_BLENDIF_RGB_BCH] = local_opacity;
339 }
340}
341
342/* multiply */
343__OMP_DECLARE_SIMD__(aligned(a, b, out:16) uniform(p, stride))
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)
346{
347 for(size_t i = 0, j = 0; i < stride; i++, j += DT_BLENDIF_RGB_CH)
348 {
349 const float local_opacity = mask[i];
350 for(int k = 0; k < DT_BLENDIF_RGB_BCH; k++)
351 {
352 out[j + k] = a[j + k] * (1.0f - local_opacity) + (a[j + k] * b[j + k] * p) * local_opacity;
353 }
354 out[j + DT_BLENDIF_RGB_BCH] = local_opacity;
355 }
356}
357
358/* add */
359__OMP_DECLARE_SIMD__(aligned(a, b, out:16) uniform(p, stride))
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)
362{
363 for(size_t i = 0, j = 0; i < stride; i++, j += DT_BLENDIF_RGB_CH)
364 {
365 const float local_opacity = mask[i];
366 for(int k = 0; k < DT_BLENDIF_RGB_BCH; k++)
367 {
368 out[j + k] = a[j + k] * (1.0f - local_opacity) + (a[j + k] + p * b[j + k]) * local_opacity;
369 }
370 out[j + DT_BLENDIF_RGB_BCH] = local_opacity;
371 }
372}
373
374/* subtract */
375__OMP_DECLARE_SIMD__(aligned(a, b, out:16) uniform(p, stride))
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)
378{
379 for(size_t i = 0, j = 0; i < stride; i++, j += DT_BLENDIF_RGB_CH)
380 {
381 const float local_opacity = mask[i];
382 for(int k = 0; k < DT_BLENDIF_RGB_BCH; k++)
383 {
384 out[j + k] = a[j + k] * (1.0f - local_opacity) + fmaxf(a[j + k] - p * b[j + k], 0.0f) * local_opacity;
385 }
386 out[j + 3] = local_opacity;
387 }
388}
389
390/* subtract inverse */
391__OMP_DECLARE_SIMD__(aligned(a, b, out:16) uniform(p, stride))
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,
394 const size_t stride)
395{
396 for(size_t i = 0, j = 0; i < stride; i++, j += DT_BLENDIF_RGB_CH)
397 {
398 const float local_opacity = mask[i];
399 for(int k = 0; k < DT_BLENDIF_RGB_BCH; k++)
400 {
401 out[j + k] = a[j + k] * (1.0f - local_opacity) + fmaxf(b[j + k] - p * a[j + k], 0.0f) * local_opacity;
402 }
403 out[j + 3] = local_opacity;
404 }
405}
406
407/* difference */
408__OMP_DECLARE_SIMD__(aligned(a, b, out:16) uniform(p, stride))
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)
411{
412 for(size_t i = 0, j = 0; i < stride; i++, j += DT_BLENDIF_RGB_CH)
413 {
414 const float local_opacity = mask[i];
415 for(int k = 0; k < DT_BLENDIF_RGB_BCH; k++)
416 {
417 out[j + k] = a[j + k] * (1.0f - local_opacity) + fabsf(a[j + k] - b[j + k]) * local_opacity;
418 }
419 out[j + DT_BLENDIF_RGB_BCH] = local_opacity;
420 }
421}
422
423/* divide */
424__OMP_DECLARE_SIMD__(aligned(a, b, out:16) uniform(p, stride))
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)
427{
428 for(size_t i = 0, j = 0; i < stride; i++, j += DT_BLENDIF_RGB_CH)
429 {
430 const float local_opacity = mask[i];
431 for(int k = 0; k < DT_BLENDIF_RGB_BCH; k++)
432 {
433 out[j + k] = a[j + k] * (1.0f - local_opacity) + a[j + k] / fmaxf(p * b[j + k], 1e-6f) * local_opacity;
434 }
435 out[j + DT_BLENDIF_RGB_BCH] = local_opacity;
436 }
437}
438
439/* divide inverse */
440__OMP_DECLARE_SIMD__(aligned(a, b, out:16) uniform(p, stride))
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)
443{
444 for(size_t i = 0, j = 0; i < stride; i++, j += DT_BLENDIF_RGB_CH)
445 {
446 const float local_opacity = mask[i];
447 for(int k = 0; k < DT_BLENDIF_RGB_BCH; k++)
448 {
449 out[j + k] = a[j + k] * (1.0f - local_opacity) + b[j + k] / fmaxf(p * a[j + k], 1e-6f) * local_opacity;
450 }
451 out[j + DT_BLENDIF_RGB_BCH] = local_opacity;
452 }
453}
454
455/* average */
456__OMP_DECLARE_SIMD__(aligned(a, b, out:16) uniform(p, stride))
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)
459{
460 for(size_t i = 0, j = 0; i < stride; i++, j += DT_BLENDIF_RGB_CH)
461 {
462 const float local_opacity = mask[i];
463 for(int k = 0; k < DT_BLENDIF_RGB_BCH; k++)
464 {
465 out[j + k] = a[j + k] * (1.0f - local_opacity) + (a[j + k] + b[j + k]) / 2.0f * local_opacity;
466 }
467 out[j + DT_BLENDIF_RGB_BCH] = local_opacity;
468 }
469}
470
471/* geometric mean */
472__OMP_DECLARE_SIMD__(aligned(a, b, out:16) uniform(p, stride))
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)
475{
476 for(size_t i = 0, j = 0; i < stride; i++, j += DT_BLENDIF_RGB_CH)
477 {
478 const float local_opacity = mask[i];
479 for(int k = 0; k < DT_BLENDIF_RGB_BCH; k++)
480 {
481 out[j + k] = a[j + k] * (1.0f - local_opacity) + sqrtf(fmax(a[j + k] * b[j + k], 0.0f)) * local_opacity;
482 }
483 out[j + DT_BLENDIF_RGB_BCH] = local_opacity;
484 }
485}
486
487/* harmonic mean */
488__OMP_DECLARE_SIMD__(aligned(a, b, out:16) uniform(p, stride))
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)
491{
492 for(size_t i = 0, j = 0; i < stride; i++, j += DT_BLENDIF_RGB_CH)
493 {
494 const float local_opacity = mask[i];
495 for(int k = 0; k < DT_BLENDIF_RGB_BCH; k++)
496 {
497 // consider that pixel values should be positive
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;
500 }
501 out[j + DT_BLENDIF_RGB_BCH] = local_opacity;
502 }
503}
504
505/* chromaticity */
506__OMP_DECLARE_SIMD__(aligned(a, b, out:16) uniform(p, stride))
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)
509{
510 for(size_t i = 0, j = 0; i < stride; i++, j += DT_BLENDIF_RGB_CH)
511 {
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);
515 for(int k = 0; k < DT_BLENDIF_RGB_BCH; k++)
516 {
517 out[j + k] = a[j + k] * (1.0f - local_opacity) + b[j + k] * norm_a / norm_b * local_opacity;
518 }
519 out[j + DT_BLENDIF_RGB_BCH] = local_opacity;
520 }
521}
522
523/* luminance */
524__OMP_DECLARE_SIMD__(aligned(a, b, out:16) uniform(p, stride))
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)
527{
528 for(size_t i = 0, j = 0; i < stride; i++, j += DT_BLENDIF_RGB_CH)
529 {
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);
533 for(int k = 0; k < DT_BLENDIF_RGB_BCH; k++)
534 {
535 out[j + k] = a[j + k] * (1.0f - local_opacity) + a[j + k] * norm_b / norm_a * local_opacity;
536 }
537 out[j + DT_BLENDIF_RGB_BCH] = local_opacity;
538 }
539}
540
541/* blend only R-channel in RGB color space without any clamping */
542__OMP_DECLARE_SIMD__(aligned(a, b, out:16) uniform(p, stride))
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)
545{
546 for(size_t i = 0, j = 0; i < stride; i++, j += DT_BLENDIF_RGB_CH)
547 {
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;
553 }
554}
555
556/* blend only R-channel in RGB color space without any clamping */
557__OMP_DECLARE_SIMD__(aligned(a, b, out:16) uniform(p, stride))
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)
560{
561 for(size_t i = 0, j = 0; i < stride; i++, j += DT_BLENDIF_RGB_CH)
562 {
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;
568 }
569}
570
571/* blend only R-channel in RGB color space without any clamping */
572__OMP_DECLARE_SIMD__(aligned(a, b, out:16) uniform(p, stride))
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)
575{
576 for(size_t i = 0, j = 0; i < stride; i++, j += DT_BLENDIF_RGB_CH)
577 {
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;
583 }
584}
585
586
587static _blend_row_func *_choose_blend_func(const unsigned int blend_mode)
588{
589 _blend_row_func *blend = NULL;
590
591 /* select the blend operator */
592 switch(blend_mode & DEVELOP_BLEND_MODE_MASK)
593 {
595 blend = _blend_multiply;
596 break;
598 blend = _blend_average;
599 break;
601 blend = _blend_add;
602 break;
604 blend = _blend_subtract;
605 break;
607 blend = _blend_subtract_inverse;
608 break;
611 blend = _blend_difference;
612 break;
614 blend = _blend_divide;
615 break;
617 blend = _blend_divide_inverse;
618 break;
620 blend = _blend_luminance;
621 break;
623 blend = _blend_chromaticity;
624 break;
626 blend = _blend_RGB_R;
627 break;
629 blend = _blend_RGB_G;
630 break;
632 blend = _blend_RGB_B;
633 break;
635 blend = _blend_geometric_mean;
636 break;
638 blend = _blend_harmonic_mean;
639 break;
640
641 /* fallback to normal blend */
642 default:
643 blend = _blend_normal;
644 break;
645 }
646
647 return blend;
648}
649
650
651__OMP_DECLARE_SIMD__(aligned(rgb: 16) uniform(profile))
652static inline float _rgb_luminance(const float *const restrict rgb,
653 const dt_iop_order_iccprofile_info_t *const restrict profile)
654{
655 float value = 0.0f;
656 if(!IS_NULL_PTR(profile))
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);
660 else
661 value = 0.3f * rgb[0] + 0.59f * rgb[1] + 0.11f * rgb[2];
662 return value;
663}
664
665__OMP_DECLARE_SIMD__(aligned(rgb, JzCzhz: 16) uniform(profile))
666static inline void _rgb_to_JzCzhz(const dt_aligned_pixel_t rgb, dt_aligned_pixel_t JzCzhz,
667 const dt_iop_order_iccprofile_info_t *const restrict profile)
668{
669 dt_aligned_pixel_t JzAzBz = { 0.0f, 0.0f, 0.0f };
670
671 if(!IS_NULL_PTR(profile))
672 {
673 dt_aligned_pixel_t XYZ_D65 = { 0.0f, 0.0f, 0.0f };
674 // use the matrix_out of the hacked profile for blending to use the
675 // conversion from RGB to XYZ D65 (instead of XYZ D50)
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);
678 dt_XYZ_2_JzAzBz(XYZ_D65, JzAzBz);
679 }
680 else
681 {
682 // This should not happen (we don't know what RGB is), but use this when profile is not defined
683 dt_XYZ_2_JzAzBz(rgb, JzAzBz);
684 }
685
686 dt_JzAzBz_2_JzCzhz(JzAzBz, JzCzhz);
687}
688
689
690__OMP_DECLARE_SIMD__(aligned(a, b:16) uniform(channel, profile, stride))
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,
694 const dt_iop_order_iccprofile_info_t *const profile)
695{
696 switch(channel)
697 {
699 {
700 const float factor = 1.0f / exp2f(boost_factors[DEVELOP_BLENDIF_RED_in]);
701 for(size_t i = 0, j = 0; i < stride; i++, j += DT_BLENDIF_RGB_CH)
702 {
703 const float c = clamp_simd(a[j + 0] * factor);
704 for(int k = 0; k < DT_BLENDIF_RGB_BCH; k++) b[j + k] = c;
705 b[j + DT_BLENDIF_RGB_BCH] = mask[i];
706 }
707 break;
708 }
710 {
711 const float factor = 1.0f / exp2f(boost_factors[DEVELOP_BLENDIF_RED_out]);
712 for(size_t i = 0, j = 0; i < stride; i++, j += DT_BLENDIF_RGB_CH)
713 {
714 const float c = clamp_simd(b[j + 0] * factor);
715 for(int k = 0; k < DT_BLENDIF_RGB_BCH; k++) b[j + k] = c;
716 b[j + DT_BLENDIF_RGB_BCH] = mask[i];
717 }
718 break;
719 }
721 {
722 const float factor = 1.0f / exp2f(boost_factors[DEVELOP_BLENDIF_GREEN_in]);
723 for(size_t i = 0, j = 0; i < stride; i++, j += DT_BLENDIF_RGB_CH)
724 {
725 const float c = clamp_simd(a[j + 1] * factor);
726 for(int k = 0; k < DT_BLENDIF_RGB_BCH; k++) b[j + k] = c;
727 b[j + DT_BLENDIF_RGB_BCH] = mask[i];
728 }
729 break;
730 }
732 {
733 const float factor = 1.0f / exp2f(boost_factors[DEVELOP_BLENDIF_GREEN_out]);
734 for(size_t i = 0, j = 0; i < stride; i++, j += DT_BLENDIF_RGB_CH)
735 {
736 const float c = clamp_simd(b[j + 1] * factor);
737 for(int k = 0; k < DT_BLENDIF_RGB_BCH; k++) b[j + k] = c;
738 b[j + DT_BLENDIF_RGB_BCH] = mask[i];
739 }
740 break;
741 }
743 {
744 const float factor = 1.0f / exp2f(boost_factors[DEVELOP_BLENDIF_BLUE_in]);
745 for(size_t i = 0, j = 0; i < stride; i++, j += DT_BLENDIF_RGB_CH)
746 {
747 const float c = clamp_simd(a[j + 2] * factor);
748 for(int k = 0; k < DT_BLENDIF_RGB_BCH; k++) b[j + k] = c;
749 b[j + DT_BLENDIF_RGB_BCH] = mask[i];
750 }
751 break;
752 }
754 {
755 const float factor = 1.0f / exp2f(boost_factors[DEVELOP_BLENDIF_BLUE_out]);
756 for(size_t i = 0, j = 0; i < stride; i++, j += DT_BLENDIF_RGB_CH)
757 {
758 const float c = clamp_simd(b[j + 2] * factor);
759 for(int k = 0; k < DT_BLENDIF_RGB_BCH; k++) b[j + k] = c;
760 b[j + DT_BLENDIF_RGB_BCH] = mask[i];
761 }
762 break;
763 }
765 {
766 const float factor = 1.0f / exp2f(boost_factors[DEVELOP_BLENDIF_GRAY_in]);
767 for(size_t i = 0, j = 0; i < stride; i++, j += DT_BLENDIF_RGB_CH)
768 {
769 const float c = clamp_simd(_rgb_luminance(a + j, profile) * factor);
770 for(int k = 0; k < DT_BLENDIF_RGB_BCH; k++) b[j + k] = c;
771 b[j + DT_BLENDIF_RGB_BCH] = mask[i];
772 }
773 break;
774 }
776 {
777 const float factor = 1.0f / exp2f(boost_factors[DEVELOP_BLENDIF_GRAY_out]);
778 for(size_t i = 0, j = 0; i < stride; i++, j += DT_BLENDIF_RGB_CH)
779 {
780 const float c = clamp_simd(_rgb_luminance(b + j, profile) * factor);
781 for(int k = 0; k < DT_BLENDIF_RGB_BCH; k++) b[j + k] = c;
782 b[j + DT_BLENDIF_RGB_BCH] = mask[i];
783 }
784 break;
785 }
787 {
788 const float factor = 1.0f / exp2f(boost_factors[DEVELOP_BLENDIF_Jz_in]);
789 for(size_t i = 0, j = 0; i < stride; i++, j += DT_BLENDIF_RGB_CH)
790 {
791 dt_aligned_pixel_t JzCzhz;
792 _rgb_to_JzCzhz(a + j, JzCzhz, profile);
793 const float c = clamp_simd(JzCzhz[0] * factor);
794 for(int k = 0; k < DT_BLENDIF_RGB_BCH; k++) b[j + k] = c;
795 b[j + DT_BLENDIF_RGB_BCH] = mask[i];
796 }
797 break;
798 }
800 {
801 const float factor = 1.0f / exp2f(boost_factors[DEVELOP_BLENDIF_Jz_out]);
802 for(size_t i = 0, j = 0; i < stride; i++, j += DT_BLENDIF_RGB_CH)
803 {
804 dt_aligned_pixel_t JzCzhz;
805 _rgb_to_JzCzhz(b + j, JzCzhz, profile);
806 const float c = clamp_simd(JzCzhz[0] * factor);
807 for(int k = 0; k < DT_BLENDIF_RGB_BCH; k++) b[j + k] = c;
808 b[j + DT_BLENDIF_RGB_BCH] = mask[i];
809 }
810 break;
811 }
813 {
814 const float factor = 1.0f / exp2f(boost_factors[DEVELOP_BLENDIF_Cz_in]);
815 for(size_t i = 0, j = 0; i < stride; i++, j += DT_BLENDIF_RGB_CH)
816 {
817 dt_aligned_pixel_t JzCzhz;
818 _rgb_to_JzCzhz(a + j, JzCzhz, profile);
819 const float c = clamp_simd(JzCzhz[1] * factor);
820 for(int k = 0; k < DT_BLENDIF_RGB_BCH; k++) b[j + k] = c;
821 b[j + DT_BLENDIF_RGB_BCH] = mask[i];
822 }
823 break;
824 }
826 {
827 const float factor = 1.0f / exp2f(boost_factors[DEVELOP_BLENDIF_Cz_out]);
828 for(size_t i = 0, j = 0; i < stride; i++, j += DT_BLENDIF_RGB_CH)
829 {
830 dt_aligned_pixel_t JzCzhz;
831 _rgb_to_JzCzhz(b + j, JzCzhz, profile);
832 const float c = clamp_simd(JzCzhz[1] * factor);
833 for(int k = 0; k < DT_BLENDIF_RGB_BCH; k++) b[j + k] = c;
834 b[j + DT_BLENDIF_RGB_BCH] = mask[i];
835 }
836 break;
837 }
839 // no boost factor for hues
840 for(size_t i = 0, j = 0; i < stride; i++, j += DT_BLENDIF_RGB_CH)
841 {
842 dt_aligned_pixel_t JzCzhz;
843 _rgb_to_JzCzhz(a + j, JzCzhz, profile);
844 const float c = clamp_simd(JzCzhz[2]);
845 for(int k = 0; k < DT_BLENDIF_RGB_BCH; k++) b[j + k] = c;
846 b[j + DT_BLENDIF_RGB_BCH] = mask[i];
847 }
848 break;
850 // no boost factor for hues
851 for(size_t i = 0, j = 0; i < stride; i++, j += DT_BLENDIF_RGB_CH)
852 {
853 dt_aligned_pixel_t JzCzhz;
854 _rgb_to_JzCzhz(b + j, JzCzhz, profile);
855 const float c = clamp_simd(JzCzhz[2]);
856 for(int k = 0; k < DT_BLENDIF_RGB_BCH; k++) b[j + k] = c;
857 b[j + DT_BLENDIF_RGB_BCH] = mask[i];
858 }
859 break;
860 default:
861 for(size_t i = 0, j = 0; i < stride; i++, j += DT_BLENDIF_RGB_CH)
862 {
863 for(int k = 0; k < DT_BLENDIF_RGB_BCH; k++) b[j + k] = 0.0f;
864 b[j + DT_BLENDIF_RGB_BCH] = mask[i];
865 }
866 break;
867 }
868}
869
870
871__OMP_DECLARE_SIMD__(aligned(a, b:16) uniform(stride))
872static inline void _copy_mask(const float *const restrict a, float *const restrict b, const size_t stride)
873{
874 __OMP_SIMD__(aligned(a, b: 16))
875 for(size_t x = DT_BLENDIF_RGB_BCH; x < stride; x += DT_BLENDIF_RGB_CH) b[x] = a[x];
876}
877
879 const struct dt_dev_pixelpipe_iop_t *piece,
880 const float *const restrict a, float *const restrict b,
881 const float *const restrict mask,
882 const dt_dev_pixelpipe_display_mask_t request_mask_display)
883{
884 const dt_iop_roi_t *const roi_in = &piece->roi_in;
885 const dt_iop_roi_t *const roi_out = &piece->roi_out;
886 const dt_develop_blend_params_t *const d = (const dt_develop_blend_params_t *const)piece->blendop_data;
887
888 if(piece->dsc_in.channels != DT_BLENDIF_RGB_CH) return;
889
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;
895
896 // only non-zero if mask_display was set by an _earlier_ module
897 const dt_dev_pixelpipe_display_mask_t mask_display = pipe->mask_display;
898
899 // process the blending operator
900 if(request_mask_display & DT_DEV_PIXELPIPE_DISPLAY_ANY)
901 {
902 dt_iop_order_iccprofile_info_t blend_profile;
903 const int use_profile = dt_develop_blendif_init_masking_profile(pipe, piece, &blend_profile,
905 const dt_iop_order_iccprofile_info_t *profile = use_profile ? &blend_profile : NULL;
906 const float *const restrict boost_factors = d->blendif_boost_factors;
907 const dt_dev_pixelpipe_display_mask_t channel = request_mask_display & DT_DEV_PIXELPIPE_DISPLAY_ANY;
909 for(size_t y = 0; y < oheight; y++)
910 {
911 const size_t a_start = ((y + yoffs) * iwidth + xoffs) * DT_BLENDIF_RGB_CH;
912 const size_t b_start = y * owidth * DT_BLENDIF_RGB_CH;
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);
915 }
916 }
917 else
918 {
919 const float p = exp2f(d->blend_parameter);
920 _blend_row_func *const blend = _choose_blend_func(d->blend_mode);
921
922 float *tmp_buffer = dt_pixelpipe_cache_alloc_align_float_cache((size_t)owidth * oheight * DT_BLENDIF_RGB_CH, 0);
923 if (!IS_NULL_PTR(tmp_buffer))
924 {
925 dt_iop_image_copy(tmp_buffer, b, (size_t)owidth * oheight * DT_BLENDIF_RGB_CH);
926 if((d->blend_mode & DEVELOP_BLEND_REVERSE) == DEVELOP_BLEND_REVERSE)
927 {
929 for(size_t y = 0; y < oheight; y++)
930 {
931 const size_t a_start = ((y + yoffs) * iwidth + xoffs) * DT_BLENDIF_RGB_CH;
932 const size_t b_start = y * owidth * DT_BLENDIF_RGB_CH;
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);
935 }
936 }
937 else
938 {
940 for(size_t y = 0; y < oheight; y++)
941 {
942 const size_t a_start = ((y + yoffs) * iwidth + xoffs) * DT_BLENDIF_RGB_CH;
943 const size_t b_start = y * owidth * DT_BLENDIF_RGB_CH;
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);
946 }
947 }
949 }
950 }
951
952 if(mask_display & DT_DEV_PIXELPIPE_DISPLAY_MASK)
953 {
954 const size_t stride = owidth * DT_BLENDIF_RGB_CH;
956 for(size_t y = 0; y < oheight; y++)
957 {
958 const size_t a_start = ((y + yoffs) * iwidth + xoffs) * DT_BLENDIF_RGB_CH;
959 const size_t b_start = y * stride;
960 _copy_mask(a + a_start, b + b_start, stride);
961 }
962 }
963}
964
965// tools/update_modelines.sh
966// remove-trailing-space on;
967// clang-format off
968// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
969// vim: shiftwidth=2 expandtab tabstop=2 cindent
970// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
971// clang-format on
void dt_develop_blendif_process_parameters(float *const restrict parameters, const dt_develop_blend_params_t *const params)
Definition blend.c:253
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)
Definition blend.c:361
@ DEVELOP_BLEND_CS_RGB_SCENE
Definition blend.h:58
@ DEVELOP_COMBINE_INV
Definition blend.h:123
@ DEVELOP_COMBINE_INCL
Definition blend.h:125
@ DEVELOP_BLENDIF_GRAY_out
Definition blend.h:156
@ DEVELOP_BLENDIF_hz_in
Definition blend.h:177
@ DEVELOP_BLENDIF_Cz_in
Definition blend.h:176
@ DEVELOP_BLENDIF_RED_in
Definition blend.h:152
@ DEVELOP_BLENDIF_GREEN_in
Definition blend.h:153
@ DEVELOP_BLENDIF_RED_out
Definition blend.h:157
@ DEVELOP_BLENDIF_Jz_out
Definition blend.h:179
@ DEVELOP_BLENDIF_Cz_out
Definition blend.h:180
@ DEVELOP_BLENDIF_Jz_in
Definition blend.h:175
@ DEVELOP_BLENDIF_BLUE_in
Definition blend.h:154
@ DEVELOP_BLENDIF_BLUE_out
Definition blend.h:159
@ DEVELOP_BLENDIF_RGB_MASK
Definition blend.h:191
@ DEVELOP_BLENDIF_GRAY_in
Definition blend.h:151
@ DEVELOP_BLENDIF_GREEN_out
Definition blend.h:158
#define DEVELOP_BLENDIF_PARAMETER_ITEMS
Definition blend.h:353
@ DEVELOP_BLEND_CHROMATICITY
Definition blend.h:80
@ DEVELOP_BLEND_DIFFERENCE
Definition blend.h:71
@ DEVELOP_BLEND_RGB_B
Definition blend.h:98
@ DEVELOP_BLEND_LIGHTNESS
Definition blend.h:79
@ DEVELOP_BLEND_SUBTRACT
Definition blend.h:70
@ DEVELOP_BLEND_MODE_MASK
Definition blend.h:107
@ DEVELOP_BLEND_DIVIDE_INVERSE
Definition blend.h:102
@ DEVELOP_BLEND_RGB_R
Definition blend.h:96
@ DEVELOP_BLEND_REVERSE
Definition blend.h:106
@ DEVELOP_BLEND_AVERAGE
Definition blend.h:68
@ DEVELOP_BLEND_DIVIDE
Definition blend.h:101
@ DEVELOP_BLEND_MULTIPLY
Definition blend.h:67
@ DEVELOP_BLEND_HARMONIC_MEAN
Definition blend.h:104
@ DEVELOP_BLEND_ADD
Definition blend.h:69
@ DEVELOP_BLEND_GEOMETRIC_MEAN
Definition blend.h:103
@ DEVELOP_BLEND_DIFFERENCE2
Definition blend.h:86
@ DEVELOP_BLEND_SUBTRACT_INVERSE
Definition blend.h:100
@ DEVELOP_BLEND_RGB_G
Definition blend.h:97
@ DEVELOP_MASK_PARAMETRIC
Definition blend.h:115
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 const float x
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
Definition develop.h:121
@ DT_DEV_PIXELPIPE_DISPLAY_OUTPUT
Definition develop.h:125
@ DT_DEV_PIXELPIPE_DISPLAY_G
Definition develop.h:130
@ DT_DEV_PIXELPIPE_DISPLAY_ANY
Definition develop.h:143
@ DT_DEV_PIXELPIPE_DISPLAY_JzCzhz_hz
Definition develop.h:140
@ DT_DEV_PIXELPIPE_DISPLAY_JzCzhz_Cz
Definition develop.h:139
@ DT_DEV_PIXELPIPE_DISPLAY_MASK
Definition develop.h:123
@ DT_DEV_PIXELPIPE_DISPLAY_JzCzhz_Jz
Definition develop.h:138
@ DT_DEV_PIXELPIPE_DISPLAY_GRAY
Definition develop.h:132
@ DT_DEV_PIXELPIPE_DISPLAY_B
Definition develop.h:131
@ DT_DEV_PIXELPIPE_DISPLAY_R
Definition develop.h:129
__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)
Definition imagebuf.c:355
__DT_CLONE_TARGETS__ void dt_iop_image_copy(float *const __restrict__ out, const float *const __restrict__ in, const size_t nfloats)
Definition imagebuf.c:142
__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)
Definition imagebuf.c:218
#define DEVELOP_BLENDIF_SIZE
Definition lightroom.c:236
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...
Definition macros.h:96
#define DT_ALIGNED_PIXEL
Align a 4-float pixel on 16 bytes, enough for SSE. Same struct-member caveat as DT_ALIGNED_ARRAY,...
Definition mem_alloc.h:85
#define DT_ALIGNED_ARRAY
Align an object on a cacheline boundary, so AVX2 can load it whole.
Definition mem_alloc.h:80
#define __OMP_SIMD__(...)
Definition openmp.h:99
#define __OMP_FOR__(...)
Definition openmp.h:98
#define __OMP_DECLARE_SIMD__(...)
Definition openmp.h:100
#define __OMP_PARALLEL__(...)
Definition openmp.h:94
#define __OMP_PARALLEL_FOR__(...)
Definition openmp.h:95
#define __OMP_FOR_SIMD__(...)
Definition openmp.h:97
#define __OMP_PARALLEL_FOR_SIMD__(...)
Definition openmp.h:96
static float clamp_simd(const float x)
const float factor
Definition pdf.h:91
#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]
Definition simd.h:53
static const dt_aligned_pixel_simd_t value
Definition simd.h:144
dt_iop_buffer_dsc_t dsc_in
unsigned int channels
Definition format.h:83
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.
Definition format.h:49
int width
Definition format.h:50
int height
Definition format.h:50