Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
blend.c
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2011-2012 Henrik Andersson.
4 Copyright (C) 2011-2016, 2018-2019 Tobias Ellinghaus.
5 Copyright (C) 2011-2014, 2016-2017, 2019 Ulrich Pegelow.
6 Copyright (C) 2011 Yclept Nemo.
7 Copyright (C) 2012 James C. McPherson.
8 Copyright (C) 2012 Richard Wonka.
9 Copyright (C) 2013 Aldric Renaudin.
10 Copyright (C) 2013 johannes hanika.
11 Copyright (C) 2013-2014, 2016 Roman Lebedev.
12 Copyright (C) 2017-2020 Heiko Bauke.
13 Copyright (C) 2017 luzpaz.
14 Copyright (C) 2018-2019 Edgardo Hoszowski.
15 Copyright (C) 2018-2021 Pascal Obry.
16 Copyright (C) 2019 Andreas Schneider.
17 Copyright (C) 2019, 2023, 2025-2026 Aurélien PIERRE.
18 Copyright (C) 2020 Felipe Contreras.
19 Copyright (C) 2020 Harold le Clément de Saint-Marcq.
20 Copyright (C) 2020-2021 Hubert Kowalski.
21 Copyright (C) 2020 U-DESKTOP-HQME86J\marco.
22 Copyright (C) 2021-2022 Hanno Schwalm.
23 Copyright (C) 2021 Ralf Brown.
24 Copyright (C) 2022 Martin Bařinka.
25 Copyright (C) 2022 Philipp Lutz.
26 Copyright (C) 2025 Miguel Moquillon.
27 Copyright (C) 2026 Guillaume Stutin.
28
29 darktable is free software: you can redistribute it and/or modify
30 it under the terms of the GNU General Public License as published by
31 the Free Software Foundation, either version 3 of the License, or
32 (at your option) any later version.
33
34 darktable is distributed in the hope that it will be useful,
35 but WITHOUT ANY WARRANTY; without even the implied warranty of
36 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
37 GNU General Public License for more details.
38
39 You should have received a copy of the GNU General Public License
40 along with darktable. If not, see <http://www.gnu.org/licenses/>.
41*/
42#include "common/darktable.h"
43#include "blend.h"
44#include "common/gaussian.h"
46#include "common/imagebuf.h"
48#include "common/opencl.h"
49#include "control/control.h"
50#include "develop/imageop.h"
51#include "develop/masks.h"
53#include "develop/supervisor.h"
54#include "develop/tiling.h"
56#include <inttypes.h>
57#include <math.h>
58#include <string.h>
59
68
69static const char *dt_pipe_type_to_str(dt_dev_pixelpipe_type_t pipe_type)
70{
71 switch(pipe_type)
72 {
74 return "PREVIEW";
76 return "FULL";
78 return "THUMBNAIL";
80 return "EXPORT";
81 default:
82 return "UNKNOWN";
83 }
84}
85
90 0.0f,
91 100.0f,
93 0,
94 0,
95 0.0f,
97 0.0f,
98 0.0f,
99 0.0f,
100 0.0f, // detail mask threshold
101 { 0, 0, 0 },
102 { 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f,
103 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f,
104 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f,
105 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f },
106 { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f },
107 { 0 }, 0, 0, FALSE };
108
110 gboolean is_scene_referred)
111{
112 if(module->flags() & IOP_FLAGS_SUPPORTS_BLENDING)
113 {
114 switch(module->blend_colorspace(module, NULL, NULL))
115 {
116 case IOP_CS_RAW:
118 case IOP_CS_LAB:
119 case IOP_CS_LCH:
121 case IOP_CS_RGB:
123 return is_scene_referred ? DEVELOP_BLEND_CS_RGB_SCENE : DEVELOP_BLEND_CS_RGB_DISPLAY;
124 case IOP_CS_HSL:
126 case IOP_CS_JZCZHZ:
128 default:
130 }
131 }
132 else
134}
135
140
143{
145 {
146 // update the default boost parameters for Jz and Cz so that the sRGB white is represented by a value
147 // "close" to 1.0. sRGB white (R=1.0, G=1.0, B=1.0) after conversion becomes Jz=0.01758 and will be shown
148 // as 1.8. In order to allow enough sensitivity in the low values, the boost factor should be set to
149 // log2(0.001) = -6.64385619. To keep the minimum boost factor at zero an offset of that value is added in
150 // the GUI. To display the initial boost factor at zero, the default value will be set to that value also.
151 blend_params->blendif_boost_factors[DEVELOP_BLENDIF_Jz_in] = -6.64385619f;
152 blend_params->blendif_boost_factors[DEVELOP_BLENDIF_Cz_in] = -6.64385619f;
153 blend_params->blendif_boost_factors[DEVELOP_BLENDIF_Jz_out] = -6.64385619f;
154 blend_params->blendif_boost_factors[DEVELOP_BLENDIF_Cz_out] = -6.64385619f;
155 }
156}
157
160{
161 memcpy(blend_params, &_default_blendop_params, sizeof(dt_develop_blend_params_t));
162 blend_params->blend_cst = cst;
163 _blend_init_blendif_boost_parameters(blend_params, cst);
164}
165
179
182{
183 const dt_develop_blend_params_t *const bp = (const dt_develop_blend_params_t *)piece->blendop_data;
184 if(IS_NULL_PTR(bp)) return cst;
185 switch(bp->blend_cst)
186 {
188 return IOP_CS_RAW;
190 return IOP_CS_LAB;
193 return IOP_CS_RGB;
194 default:
195 return cst;
196 }
197}
198
199void dt_develop_blendif_process_parameters(float *const restrict parameters,
200 const dt_develop_blend_params_t *const params)
201{
202 const int32_t blend_csp = params->blend_cst;
203 const uint32_t blendif = params->blendif;
204 const float *blendif_parameters = params->blendif_parameters;
205 const float *boost_factors = params->blendif_boost_factors;
206 for(size_t i = 0, j = 0; i < DEVELOP_BLENDIF_SIZE; i++, j += DEVELOP_BLENDIF_PARAMETER_ITEMS)
207 {
208 if(blendif & (1 << i))
209 {
210 float offset = 0.0f;
213 {
214 offset = 0.5f;
215 }
216 parameters[j + 0] = (blendif_parameters[i * 4 + 0] - offset) * exp2f(boost_factors[i]);
217 parameters[j + 1] = (blendif_parameters[i * 4 + 1] - offset) * exp2f(boost_factors[i]);
218 parameters[j + 2] = (blendif_parameters[i * 4 + 2] - offset) * exp2f(boost_factors[i]);
219 parameters[j + 3] = (blendif_parameters[i * 4 + 3] - offset) * exp2f(boost_factors[i]);
220 // pre-compute increasing slope and decreasing slope
221 parameters[j + 4] = 1.0f / fmaxf(0.001f, parameters[j + 1] - parameters[j + 0]);
222 parameters[j + 5] = 1.0f / fmaxf(0.001f, parameters[j + 3] - parameters[j + 2]);
223 // handle the case when one end is open to avoid clipping input/output values
224 if(blendif_parameters[i * 4 + 0] <= 0.0f && blendif_parameters[i * 4 + 1] <= 0.0f)
225 {
226 parameters[j + 0] = -INFINITY;
227 parameters[j + 1] = -INFINITY;
228 }
229 if(blendif_parameters[i * 4 + 2] >= 1.0f && blendif_parameters[i * 4 + 3] >= 1.0f)
230 {
231 parameters[j + 2] = INFINITY;
232 parameters[j + 3] = INFINITY;
233 }
234 }
235 else
236 {
237 parameters[j + 0] = -INFINITY;
238 parameters[j + 1] = -INFINITY;
239 parameters[j + 2] = INFINITY;
240 parameters[j + 3] = INFINITY;
241 parameters[j + 4] = 0.0f;
242 parameters[j + 5] = 0.0f;
243 }
244 }
245}
246
248 const dt_develop_blend_params_t *params,
249 gboolean *top_enabled,
250 gboolean *raster_used,
251 gboolean *drawn_used,
252 gboolean *parametric_used)
253{
254 if(!IS_NULL_PTR(top_enabled)) *top_enabled = FALSE;
255 if(!IS_NULL_PTR(raster_used)) *raster_used = FALSE;
256 if(!IS_NULL_PTR(drawn_used)) *drawn_used = FALSE;
257 if(!IS_NULL_PTR(parametric_used)) *parametric_used = FALSE;
258 if(IS_NULL_PTR(params)) return;
259
260 const uint32_t mask_mode = params->mask_mode;
261 const gboolean top = (mask_mode & DEVELOP_MASK_ENABLED) != 0;
262 const gboolean raster_mode = (mask_mode & DEVELOP_MASK_RASTER) != 0;
263 const gboolean drawn_mode = (mask_mode & DEVELOP_MASK_SHAPE) != 0;
264 const gboolean parametric_mode = (mask_mode & DEVELOP_MASK_PARAMETRIC) != 0;
265
266 gboolean raster = raster_mode
267 && (params->raster_mask_id > 0
268 || params->raster_mask_source[0] != '\0'
269 || (!IS_NULL_PTR(module) && !IS_NULL_PTR(module->raster_mask.sink.source)));
270
271 gboolean drawn = FALSE;
272 if(drawn_mode && !IS_NULL_PTR(module) && !IS_NULL_PTR(module->dev))
273 {
274 dt_masks_form_t *grp = dt_masks_get_from_id(module->dev, params->mask_id);
275 drawn = !IS_NULL_PTR(grp) && (grp->type & DT_MASKS_GROUP) && g_list_length(grp->points) > 0;
276 }
277
278 gboolean parametric = FALSE;
279 if(parametric_mode)
280 {
281 const float threshold_epsilon = 1e-6f;
282 const uint32_t channel_mask = params->blend_cst == DEVELOP_BLEND_CS_LAB
285 uint32_t active_channels = 0;
286 for(uint32_t ch = 0; ch < DEVELOP_BLENDIF_SIZE; ch++)
287 {
288 const uint32_t bit = 1u << ch;
289 if(!(channel_mask & bit) || !(params->blendif & bit)) continue;
290 const float *channel = &params->blendif_parameters[ch * 4];
291 if(fabsf(channel[0]) > threshold_epsilon
292 || fabsf(channel[1]) > threshold_epsilon
293 || fabsf(channel[2] - 1.0f) > threshold_epsilon
294 || fabsf(channel[3] - 1.0f) > threshold_epsilon)
295 active_channels |= bit;
296 }
297 parametric = active_channels != 0;
298 }
299
300 if(!IS_NULL_PTR(top_enabled)) *top_enabled = top;
301 if(!IS_NULL_PTR(raster_used)) *raster_used = raster;
302 if(!IS_NULL_PTR(drawn_used)) *drawn_used = drawn;
303 if(!IS_NULL_PTR(parametric_used)) *parametric_used = parametric;
304}
305
306// See function definition in blend.h for important information
308 const struct dt_dev_pixelpipe_iop_t *piece,
309 dt_iop_order_iccprofile_info_t *blending_profile,
311{
312 // Bradford adaptation matrix from http://www.brucelindbloom.com/index.html?Eqn_ChromAdapt.html
313 const dt_colormatrix_t M = {
314 { 0.9555766f, -0.0230393f, 0.0631636f, 0.0f },
315 { -0.0282895f, 1.0099416f, 0.0210077f, 0.0f },
316 { 0.0122982f, -0.0204830f, 1.3299098f, 0.0f },
317 };
318
319 const dt_iop_order_iccprofile_info_t *const profile = (cst == DEVELOP_BLEND_CS_RGB_SCENE)
320 ? dt_ioppr_get_pipe_current_profile_info(piece->module, pipe)
321 : dt_ioppr_get_iop_work_profile_info(piece->module, piece->module->dev->iop);
322 if(IS_NULL_PTR(profile)) return 0;
323
324 memcpy(blending_profile, profile, sizeof(dt_iop_order_iccprofile_info_t));
325 for(size_t y = 0; y < 3; y++)
326 {
327 for(size_t x = 0; x < 3; x++)
328 {
329 float sum = 0.0f;
330 for(size_t i = 0; i < 3; i++)
331 sum += M[y][i] * profile->matrix_in[i][x];
332 blending_profile->matrix_out[y][x] = sum;
333 blending_profile->matrix_out_transposed[x][y] = sum;
334 }
335 }
336
337 return 1;
338}
339
340static inline float _detail_mask_threshold(const float level, const gboolean detail)
341{
342 // this does some range calculation for smoother ui experience
343 return 0.005f * (detail ? powf(level, 2.0f) : 1.0f - powf(fabs(level), 0.5f ));
344}
345
346static void _refine_with_detail_mask(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe,
347 const struct dt_dev_pixelpipe_iop_t *piece, float *mask,
348 const float level)
349{
350 const dt_iop_roi_t *const roi_out = &piece->roi_out;
351 if(level == 0.0f) return;
352 const gboolean info = ((darktable.unmuted & DT_DEBUG_MASKS) && (pipe->type == DT_DEV_PIXELPIPE_FULL));
353
354 const gboolean detail = (level > 0.0f);
355 const float threshold = _detail_mask_threshold(level, detail);
356
357 float *tmp = NULL;
358 float *lum = NULL;
359 float *warp_mask = NULL;
360 float *rawdetail_mask = NULL;
361
362 const dt_dev_pixelpipe_t *p = pipe;
363 rawdetail_mask = dt_dev_retrieve_rawdetail_mask(pipe, self);
364 if(IS_NULL_PTR(rawdetail_mask)) return;
365
366 const int iwidth = p->rawdetail_mask_roi.width;
367 const int iheight = p->rawdetail_mask_roi.height;
368 const int owidth = roi_out->width;
369 const int oheight = roi_out->height;
370 if(info) fprintf(stderr, "[_refine_with_detail_mask] in module %s %ix%i --> %ix%i\n", self->op, iwidth, iheight, owidth, oheight);
371
372 const int bufsize = MAX(iwidth * iheight, owidth * oheight);
373
374 tmp = dt_pixelpipe_cache_alloc_align_float(bufsize, pipe);
375 lum = dt_pixelpipe_cache_alloc_align_float(bufsize, pipe);
376 if((IS_NULL_PTR(tmp)) || (IS_NULL_PTR(lum))) goto error;
377
378 dt_masks_calc_detail_mask(rawdetail_mask, lum, tmp, iwidth, iheight, threshold, detail);
380 tmp = NULL;
381
382 // here we have the slightly blurred full detail mask available
383 warp_mask = dt_dev_distort_detail_mask(p, lum, self);
384 // dt_dev_distort_detail_mask() may return `lum` unchanged when no geometric distortion is needed.
385 const gboolean warp_mask_aliases_lum = (warp_mask == lum);
386 if(!warp_mask_aliases_lum)
387 {
389 lum = NULL;
390 }
391
392 if(IS_NULL_PTR(warp_mask)) goto error;
393
394 const int msize = owidth * oheight;
395 __OMP_PARALLEL_FOR_SIMD__(aligned(mask, warp_mask : 64))
396 for(int idx =0; idx < msize; idx++)
397 {
398 mask[idx] = mask[idx] * warp_mask[idx];
399 }
401 if(warp_mask_aliases_lum) lum = NULL;
402
403 return;
404
405 error:
406 dt_control_log(_("detail mask blending error"));
410}
411
413 const dt_dev_pixelpipe_iop_t *const piece,
414 _develop_mask_post_processing operations[3])
415{
416 const gboolean mask_feather = params->feathering_radius > 0.1f && piece->dsc_in.channels >= 3;
417 const gboolean mask_blur = params->blur_radius > 0.1f;
418 const gboolean mask_tone_curve = fabsf(params->contrast) >= 0.01f || fabsf(params->brightness) >= 0.01f;
419 const gboolean mask_feather_before = params->feathering_guide == DEVELOP_MASK_GUIDE_IN_BEFORE_BLUR
420 || params->feathering_guide == DEVELOP_MASK_GUIDE_OUT_BEFORE_BLUR;
421 const gboolean mask_feather_out = params->feathering_guide == DEVELOP_MASK_GUIDE_OUT_BEFORE_BLUR
422 || params->feathering_guide == DEVELOP_MASK_GUIDE_OUT_AFTER_BLUR;
423 const float opacity = fminf(fmaxf(params->opacity / 100.0f, 0.0f), 1.0f);
424
425 memset(operations, 0, sizeof(_develop_mask_post_processing) * 3);
426 size_t index = 0;
427
428 if(mask_feather)
429 {
430 if(mask_blur && mask_feather_before)
431 {
432 operations[index++] = mask_feather_out ? DEVELOP_MASK_POST_FEATHER_OUT : DEVELOP_MASK_POST_FEATHER_IN;
433 operations[index++] = DEVELOP_MASK_POST_BLUR;
434 }
435 else
436 {
437 if(mask_blur)
438 operations[index++] = DEVELOP_MASK_POST_BLUR;
439 operations[index++] = mask_feather_out ? DEVELOP_MASK_POST_FEATHER_OUT : DEVELOP_MASK_POST_FEATHER_IN;
440 }
441 }
442 else if(mask_blur)
443 {
444 operations[index++] = DEVELOP_MASK_POST_BLUR;
445 }
446
447 if(mask_tone_curve && opacity > 1e-4f)
448 {
449 operations[index++] = DEVELOP_MASK_POST_TONE_CURVE;
450 }
451
452 return index;
453}
454
455
456static inline float *_develop_blend_process_copy_region(const float *const restrict input, const size_t iwidth,
457 const size_t xoffs, const size_t yoffs,
458 const size_t owidth, const size_t oheight)
459{
460 const size_t ioffset = yoffs * iwidth + xoffs;
461 float *const restrict output =
463 if(IS_NULL_PTR(output))
464 {
465 return NULL;
466 }
468 for(size_t y = 0; y < oheight; y++)
469 {
470 const size_t iindex = y * iwidth + ioffset;
471 const size_t oindex = y * owidth;
472 memcpy(output + oindex, input + iindex, sizeof(float) * owidth);
473 }
474
475 return output;
476}
477
478static inline void _develop_blend_process_free_region(float *const restrict input)
479{
481}
482
484 const dt_iop_module_t *const self)
485{
486 if(IS_NULL_PTR(params) || IS_NULL_PTR(self)) return NULL;
487
488 const dt_iop_module_t *source = self->raster_mask.sink.source;
489 if(source && !strcmp(source->op, params->raster_mask_source)
490 && source->multi_priority == params->raster_mask_instance)
491 return source;
492
493 if(IS_NULL_PTR(self->dev) || params->raster_mask_source[0] == '\0') return NULL;
494
495 for(GList *iter = g_list_first(self->dev->iop); iter; iter = g_list_next(iter))
496 {
497 const dt_iop_module_t *candidate = (const dt_iop_module_t *)iter->data;
498 if(!strcmp(candidate->op, params->raster_mask_source)
499 && candidate->multi_priority == params->raster_mask_instance)
500 return candidate;
501 }
502
503 return NULL;
504}
505
507 dt_iop_module_t *self,
508 dt_dev_pixelpipe_t *pipe,
509 const dt_dev_pixelpipe_iop_t *piece,
510 float *const restrict mask,
511 const size_t owidth,
512 const size_t oheight,
513 int *const raster_error)
514{
515 int local_raster_error = 0;
516 const dt_iop_module_t *raster_source = _develop_blend_get_raster_source_module(params, self);
517 float *raster_mask = raster_source
518 ? dt_dev_get_raster_mask(pipe, raster_source, params->raster_mask_id,
519 self, &local_raster_error)
520 : NULL;
521
522 if(!IS_NULL_PTR(raster_mask))
523 {
524 if(params->raster_mask_invert)
525 {
526 __OMP_FOR_SIMD__(aligned(mask, raster_mask:64) )
527 for(size_t i = 0; i < owidth * oheight; i++)
528 mask[i] = 1.0f - raster_mask[i];
529 }
530 else
531 {
532 dt_iop_image_scaled_copy(mask, raster_mask, 1.0f, owidth, oheight, 1);
533 }
534
536 }
537 else
538 {
539 const float value = params->raster_mask_invert ? 0.0f : 1.0f;
540 dt_iop_image_fill(mask, value, owidth, oheight, 1);
541 }
542
543 if(!IS_NULL_PTR(raster_error)) *raster_error = local_raster_error;
544}
545
547 dt_iop_module_t *self,
548 dt_dev_pixelpipe_t *pipe,
549 const dt_dev_pixelpipe_iop_t *piece,
550 const struct dt_iop_roi_t *const roi_out,
551 float *const restrict mask,
552 const size_t owidth,
553 const size_t oheight)
554{
555 dt_masks_form_t *form = dt_masks_get_from_id(self->dev, params->mask_id);
556
557 if(form && (!(self->flags() & IOP_FLAGS_NO_MASKS)) && (params->mask_mode & DEVELOP_MASK_SHAPE))
558 {
559 if(dt_masks_group_render_roi(self, pipe, piece, form, roi_out, mask) != 0) return 1;
560
561 if(params->mask_combine & DEVELOP_COMBINE_MASKS_POS)
562 dt_iop_image_invert(mask, 1.0f, owidth, oheight, 1);
563 }
564 else if((!(self->flags() & IOP_FLAGS_NO_MASKS)) && (params->mask_mode & DEVELOP_MASK_SHAPE))
565 {
566 const float fill = (params->mask_combine & DEVELOP_COMBINE_MASKS_POS) ? 0.0f : 1.0f;
567 dt_iop_image_fill(mask, fill, owidth, oheight, 1);
568 }
569 else
570 {
571 const float fill = (params->mask_combine & DEVELOP_COMBINE_INCL) ? 0.0f : 1.0f;
572 dt_iop_image_fill(mask, fill, owidth, oheight, 1);
573 }
574
575 return 0;
576}
577
578static void _develop_blend_combine_masks(float *const restrict mask,
579 const float *const restrict other_mask,
580 const size_t buffsize)
581{
582 __OMP_FOR_SIMD__(aligned(mask, other_mask:64) )
583 for(size_t i = 0; i < buffsize; i++)
584 mask[i] *= other_mask[i];
585}
586
587
588static int _develop_blend_process_feather(const float *const guide, float *const mask, const size_t width,
589 const size_t height, const int ch, const float guide_weight,
590 const float feathering_radius, const float scale)
591{
592 const float sqrt_eps = 1.f;
593 int w = (int)(2 * feathering_radius * scale + 0.5f);
594 if(w < 1) w = 1;
595
596 float *const restrict mask_bak =
598 if(IS_NULL_PTR(mask_bak)) return 1;
599
600 memcpy(mask_bak, mask, sizeof(float) * width * height);
601 if(guided_filter(guide, mask_bak, mask, width, height, ch, w, sqrt_eps, guide_weight, 0.f, 1.f) != 0)
602 {
604 return 1;
605 }
607 return 0;
608}
609
610
611static void _develop_blend_process_mask_tone_curve(float *const restrict mask, const size_t buffsize,
612 const float contrast, const float brightness,
613 const float opacity)
614{
615 const float mask_epsilon = 16 * FLT_EPSILON; // empirical mask threshold for fully transparent masks
616 const float e = expf(3.f * contrast);
617 __OMP_PARALLEL_FOR_SIMD__(aligned(mask:64))
618 for(size_t k = 0; k < buffsize; k++)
619 {
620 float x = mask[k] / opacity;
621 x = 2.f * x - 1.f;
622 if (1.f - brightness <= 0.f)
623 x = mask[k] <= mask_epsilon ? -1.f : 1.f;
624 else if (1.f + brightness <= 0.f)
625 x = mask[k] >= 1.f - mask_epsilon ? 1.f : -1.f;
626 else if (brightness > 0.f)
627 {
628 x = (x + brightness) / (1.f - brightness);
629 x = fminf(x, 1.f);
630 }
631 else
632 {
633 x = (x + brightness) / (1.f + brightness);
634 x = fmaxf(x, -1.f);
635 }
636 mask[k] = clamp_range_f(
637 ((x * e / (1.f + (e - 1.f) * fabsf(x))) / 2.f + 0.5f) * opacity, 0.f, 1.f);
638 }
639}
640
641
643 const struct dt_dev_pixelpipe_iop_t *piece, const void *const ivoid,
644 void *const ovoid)
645{
646 const dt_iop_roi_t *const roi_in = &piece->roi_in;
647 const dt_iop_roi_t *const roi_out = &piece->roi_out;
648 if(pipe->bypass_blendif && self->dev->gui_attached && (self == self->dev->gui_module)) return 0;
649
650 const dt_develop_blend_params_t *const d = (const dt_develop_blend_params_t *const)piece->blendop_data;
651 if(IS_NULL_PTR(d)) return 0;
652
653 gboolean top_enabled = FALSE;
654 gboolean raster_used = FALSE;
655 gboolean drawn_used = FALSE;
656 gboolean parametric_used = FALSE;
657 dt_develop_blend_get_mask_usage(self, d, &top_enabled, &raster_used, &drawn_used, &parametric_used);
658 if(!top_enabled) return 0;
659 // A mask preview request must also be honored when every sub-mask is neutral.
660 // In that case no raster/drawn/parametric mask is "used", but the effective
661 // blend mask is still the uniform opacity mask written into alpha below.
662 const gboolean preview_mask_mode = top_enabled;
663
664 const size_t ch = piece->dsc_in.channels; // the number of channels in the buffer
665 const int xoffs = roi_out->x - roi_in->x;
666 const int yoffs = roi_out->y - roi_in->y;
667 const int iwidth = roi_in->width;
668 const int iheight = roi_in->height;
669 const int owidth = roi_out->width;
670 const int oheight = roi_out->height;
671 const size_t buffsize = (size_t)owidth * oheight;
672 const float iscale = roi_in->scale;
673 const float oscale = roi_out->scale;
674 const gboolean rois_equal = iwidth == owidth || iheight == oheight || xoffs == 0 || yoffs == 0;
675
676 // In most cases of blending-enabled modules input and output of the module have
677 // the exact same dimensions. Only in very special cases we allow a module's input
678 // to exceed its output. This is namely the case for the spot removal module where
679 // the source of a patch might lie outside the roi of the output image. Therefore:
680 // We can only handle blending if roi_out and roi_in have the same scale and
681 // if roi_out fits into the area given by roi_in. xoffs and yoffs describe the relative
682 // offset of the input image to the output image.
683 if(oscale != iscale || xoffs < 0 || yoffs < 0
684 || ((xoffs > 0 || yoffs > 0) && (owidth + xoffs > iwidth || oheight + yoffs > iheight)))
685 {
686 dt_control_log(_("skipped blending in module '%s': roi's do not match"), self->op);
687 return 0;
688 }
689
690 // does user want us to display a specific channel?
691 const dt_dev_pixelpipe_display_mask_t request_mask_display =
692 (self->dev->gui_attached && (self == self->dev->gui_module) && (pipe == self->dev->pipe)
693 && preview_mask_mode)
696
697 // get channel max values depending on colorspace
698 const dt_develop_blend_colorspace_t blend_csp = d->blend_cst;
700
701 // obtaining the list of mask operations to perform
702 _develop_mask_post_processing post_operations[3];
703 const size_t post_operations_size = _develop_mask_get_post_operations(d, piece, post_operations);
704
705 // get the clipped opacity value 0 - 1
706 const float opacity = fminf(fmaxf(d->opacity / 100.0f, 0.0f), 1.0f);
707
708 // allocate space for blend mask
709 float *const restrict _mask = dt_pixelpipe_cache_alloc_align_float(buffsize, pipe);
710 if(IS_NULL_PTR(_mask))
711 {
712 dt_control_log(_("could not allocate buffer for blending"));
713 return 1;
714 }
715 int raster_error = 0;
716 float *const restrict mask = _mask;
717 const gboolean use_masks = raster_used || drawn_used || parametric_used;
718 const gboolean raster_only = raster_used && !drawn_used && !parametric_used;
719
720 if(!use_masks)
721 {
722 // blend uniformly (no drawn or parametric mask)
723 dt_iop_image_fill(mask,opacity,owidth,oheight,1); //mask[k] = opacity;
724 }
725 else if(raster_only)
726 {
727 /* use a raster mask from another module earlier in the pipe */
728 _develop_blend_init_raster_mask(d, self, pipe, piece, mask, owidth, oheight, &raster_error);
729 dt_iop_image_mul_const(mask, opacity, owidth, oheight, 1);
730 }
731 else
732 {
733 if(!raster_used && !drawn_used)
734 {
735 // Parametric-only blending has no raster/drawn form mask to seed `mask`.
736 // The combination code below loops on parametric channels and composes them
737 // with that form mask, so initialize it as the neutral value of the chosen
738 // mask-combine operator.
739 const float fill = (d->mask_combine & DEVELOP_COMBINE_INCL) ? 0.0f : 1.0f;
740 dt_iop_image_fill(mask, fill, owidth, oheight, 1);
741 }
742 else if(raster_used)
743 {
744 _develop_blend_init_raster_mask(d, self, pipe, piece, mask, owidth, oheight, &raster_error);
745
746 if(drawn_used)
747 {
748 float *const restrict drawn_mask = dt_pixelpipe_cache_alloc_align_float(buffsize, pipe);
749 if(IS_NULL_PTR(drawn_mask))
750 {
751 dt_control_log(_("could not allocate buffer for blending"));
753 return 1;
754 }
755
756 if(_develop_blend_init_drawn_mask(d, self, pipe, piece, roi_out, drawn_mask, owidth, oheight) != 0)
757 {
760 return 1;
761 }
762
763 _develop_blend_combine_masks(mask, drawn_mask, buffsize);
765 }
766 }
767 else if(drawn_used
768 && _develop_blend_init_drawn_mask(d, self, pipe, piece, roi_out, mask, owidth, oheight) != 0)
769 {
771 return 1;
772 }
773
774 _refine_with_detail_mask(self, pipe, piece, mask, d->details);
775
776 // get parametric mask (if any) and apply global opacity
777 switch(blend_csp)
778 {
780 dt_develop_blendif_lab_make_mask(piece, (const float *const restrict)ivoid,
781 (const float *const restrict)ovoid, mask);
782 break;
784 dt_develop_blendif_rgb_hsl_make_mask(pipe, piece, (const float *const restrict)ivoid,
785 (const float *const restrict)ovoid, mask);
786 break;
788 dt_develop_blendif_rgb_jzczhz_make_mask(pipe, piece, (const float *const restrict)ivoid,
789 (const float *const restrict)ovoid, mask);
790 break;
792 dt_develop_blendif_raw_make_mask(piece, (const float *const restrict)ivoid,
793 (const float *const restrict)ovoid, mask);
794 break;
795 default:
796 break;
797 }
798
799 // post processing the mask
800 for(size_t index = 0; index < post_operations_size; ++index)
801 {
802 _develop_mask_post_processing operation = post_operations[index];
803 if(operation == DEVELOP_MASK_POST_FEATHER_IN)
804 {
805 const float guide_weight = dt_iop_colorspace_is_rgb(cst) ? 100.0f : 1.0f;
806 float *restrict guide = (float *restrict)ivoid;
807 if(!rois_equal)
808 guide = _develop_blend_process_copy_region(guide, ch * iwidth, ch * xoffs, ch * yoffs,
809 ch * owidth, ch * oheight);
810 if(!guide)
811 {
813 return 1;
814 }
815 if(_develop_blend_process_feather(guide, mask, owidth, oheight, ch, guide_weight,
816 d->feathering_radius, roi_out->scale) != 0)
817 {
818 if(!rois_equal)
821 return 1;
822 }
823 if(!rois_equal)
825 }
826 else if(operation == DEVELOP_MASK_POST_FEATHER_OUT)
827 {
828 const float guide_weight = dt_iop_colorspace_is_rgb(cst) ? 100.0f : 1.0f;
829 if(_develop_blend_process_feather((const float *const restrict)ovoid, mask, owidth, oheight, ch,
830 guide_weight, d->feathering_radius, roi_out->scale) != 0)
831 {
833 return 1;
834 }
835 }
836 else if(operation == DEVELOP_MASK_POST_BLUR)
837 {
838 const float sigma = d->blur_radius * roi_out->scale;
839 const float mmax[] = { 1.0f };
840 const float mmin[] = { 0.0f };
841
842 dt_gaussian_t *g = dt_gaussian_init(owidth, oheight, 1, mmax, mmin, sigma, 0);
843 if(g)
844 {
845 dt_gaussian_blur(g, mask, mask);
847 }
848 }
849 else if(operation == DEVELOP_MASK_POST_TONE_CURVE)
850 {
851 _develop_blend_process_mask_tone_curve(mask, buffsize, d->contrast, d->brightness, opacity);
852 }
853 }
854 }
855
856 // now apply blending with per-pixel opacity value as defined in mask
857 // select the blend operator
858 switch(blend_csp)
859 {
861 dt_develop_blendif_lab_blend(pipe, piece, (const float *const restrict)ivoid, (float *const restrict)ovoid,
862 mask, request_mask_display);
863 break;
865 dt_develop_blendif_rgb_hsl_blend(pipe, piece, (const float *const restrict)ivoid, (float *const restrict)ovoid,
866 mask, request_mask_display);
867 break;
869 dt_develop_blendif_rgb_jzczhz_blend(pipe, piece, (const float *const restrict)ivoid, (float *const restrict)ovoid,
870 mask, request_mask_display);
871 break;
873 dt_develop_blendif_raw_blend(pipe, piece, (const float *const restrict)ivoid, (float *const restrict)ovoid,
874 mask, request_mask_display);
875 break;
876 default:
877 break;
878 }
879
880 // register if _this_ module should expose mask or display channel
882 {
883 pipe->mask_display = request_mask_display;
884 }
885
886 // check if we should store the mask for export or use in subsequent modules
888 {
889 const uint64_t mask_hash = dt_dev_pixelpipe_raster_mask_hash(piece, 0);
890 dt_pixel_cache_entry_t *mask_entry = NULL;
891 void *cache_data = NULL;
892 const int created = dt_dev_pixelpipe_cache_get(
893 darktable.pixelpipe_cache, mask_hash, sizeof(float) * buffsize,
894 "raster mask", pipe->type, TRUE, &cache_data, &mask_entry);
895
896 if(IS_NULL_PTR(cache_data) || IS_NULL_PTR(mask_entry))
897 {
898 if(created && !IS_NULL_PTR(mask_entry))
900 if(!IS_NULL_PTR(mask_entry))
901 {
903 if(created)
905 }
907 return 1;
908 }
909
910 // Cache entries are immutable for a given provider state. Only the thread
911 // which created this dedicated key writes the mask; exact hits reuse it.
912 if(created)
913 {
914 memcpy(cache_data, _mask, sizeof(float) * buffsize);
916 }
917 // Transfer cache_get()'s reference to the pipe. It keeps this side-band
918 // output alive until the next graph state is prepared or the pipe closes.
919 g_array_append_val(pipe->raster_mask_hashes, mask_hash);
921
922 if(created && dt_supervisor_active())
924 dt_supervisor_node_key(pipe->type, piece->module->op,
925 piece->module->multi_priority),
926 piece->hash, piece->global_hash, piece->module->op,
927 piece->module->multi_priority, piece->module->iop_order,
928 pipe->type, pipe->imgid, piece->roi_out.width,
929 piece->roi_out.height, -1, sizeof(float) * buffsize,
930 "raster mask");
931
933 "[raster masks] %s mask id 0 for module %s (%s) for pipe %s"
934 " with cache hash %" PRIu64 "\n",
935 created ? "published" : "reused cached",
936 piece->module->op, piece->module->multi_name,
937 dt_pipe_type_to_str(pipe->type), mask_hash);
938 }
939 else
940 {
942 "[raster masks] discarding unpublished mask id 0 for module %s (%s) for pipe %s\n",
943 piece->module->op, piece->module->multi_name,
946 }
947 // raster error is the only one we catch
948 return raster_error;
949}
950
951#ifdef HAVE_OPENCL
952static void _refine_with_detail_mask_cl(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe,
953 const struct dt_dev_pixelpipe_iop_t *piece, float *mask,
954 const float level, const int devid)
955{
956 const dt_iop_roi_t *const roi_out = &piece->roi_out;
957 if(level == 0.0f) return;
958 const gboolean info = (darktable.unmuted & DT_DEBUG_MASKS);
959
960 const int detail = (level > 0.0f);
961 const float threshold = _detail_mask_threshold(level, detail);
962 float *lum = NULL;
963 float *rawdetail_mask = NULL;
964 cl_mem tmp = NULL;
965 cl_mem blur = NULL;
966 cl_mem out = NULL;
967
968 const dt_dev_pixelpipe_t *p = pipe;
969 rawdetail_mask = dt_dev_retrieve_rawdetail_mask(pipe, self);
970 if(IS_NULL_PTR(rawdetail_mask)) return;
971
972 const int iwidth = p->rawdetail_mask_roi.width;
973 const int iheight = p->rawdetail_mask_roi.height;
974 const int owidth = roi_out->width;
975 const int oheight = roi_out->height;
976 if(info) fprintf(stderr, "[_refine_with_detail_mask_cl] in module %s %ix%i --> %ix%i\n", self->op, iwidth, iheight, owidth, oheight);
977
978 lum = dt_pixelpipe_cache_alloc_align_float((size_t)iwidth * iheight, pipe);
979 if(IS_NULL_PTR(lum)) goto error;
980 tmp = dt_opencl_alloc_device(devid, iwidth, iheight, sizeof(float));
981 if(IS_NULL_PTR(tmp)) goto error;
982 out = dt_opencl_alloc_device_buffer(devid, sizeof(float) * iwidth * iheight);
983 if(IS_NULL_PTR(out)) goto error;
984 blur = dt_opencl_alloc_device_buffer(devid, sizeof(float) * iwidth * iheight);
985 if(IS_NULL_PTR(blur)) goto error;
986
987 {
988 const int err = dt_opencl_write_host_to_device(devid, rawdetail_mask, tmp, iwidth, iheight, sizeof(float));
989 if(err != CL_SUCCESS) goto error;
990 }
991
992 {
993 size_t sizes[3] = { ROUNDUPDWD(iwidth, devid), ROUNDUPDHT(iheight, devid), 1 };
995 dt_opencl_set_kernel_arg(devid, kernel, 0, sizeof(cl_mem), &out);
996 dt_opencl_set_kernel_arg(devid, kernel, 1, sizeof(cl_mem), &tmp);
997 dt_opencl_set_kernel_arg(devid, kernel, 2, sizeof(int), &iwidth);
998 dt_opencl_set_kernel_arg(devid, kernel, 3, sizeof(int), &iheight);
999 const int err = dt_opencl_enqueue_kernel_2d(devid, kernel, sizes);
1000 if(err != CL_SUCCESS) goto error;
1001 }
1002
1003 {
1004 size_t sizes[3] = { ROUNDUPDWD(iwidth, devid), ROUNDUPDHT(iheight, devid), 1 };
1006 dt_opencl_set_kernel_arg(devid, kernel, 0, sizeof(cl_mem), &out);
1007 dt_opencl_set_kernel_arg(devid, kernel, 1, sizeof(cl_mem), &blur);
1008 dt_opencl_set_kernel_arg(devid, kernel, 2, sizeof(int), &iwidth);
1009 dt_opencl_set_kernel_arg(devid, kernel, 3, sizeof(int), &iheight);
1010 dt_opencl_set_kernel_arg(devid, kernel, 4, sizeof(float), &threshold);
1011 dt_opencl_set_kernel_arg(devid, kernel, 5, sizeof(int), &detail);
1012 const int err = dt_opencl_enqueue_kernel_2d(devid, kernel, sizes);
1013 if(err != CL_SUCCESS) goto error;
1014 }
1015
1016 {
1017 float blurmat[13];
1018 dt_masks_blur_9x9_coeff(blurmat, 2.0f);
1019 cl_mem dev_blurmat = NULL;
1020 dev_blurmat = dt_opencl_copy_host_to_device_constant(devid, sizeof(float) * 13, blurmat);
1021 if(!IS_NULL_PTR(dev_blurmat))
1022 {
1023 size_t sizes[3] = { ROUNDUPDWD(iwidth, devid), ROUNDUPDHT(iheight, devid), 1 };
1024 const int clkernel = darktable.opencl->blendop->kernel_mask_blur;
1025 dt_opencl_set_kernel_arg(devid, clkernel, 0, sizeof(cl_mem), &blur);
1026 dt_opencl_set_kernel_arg(devid, clkernel, 1, sizeof(cl_mem), &out);
1027 dt_opencl_set_kernel_arg(devid, clkernel, 2, sizeof(int), &iwidth);
1028 dt_opencl_set_kernel_arg(devid, clkernel, 3, sizeof(int), &iheight);
1029 dt_opencl_set_kernel_arg(devid, clkernel, 4, sizeof(cl_mem), (void *) &dev_blurmat);
1030 const int err = dt_opencl_enqueue_kernel_2d(devid, clkernel, sizes);
1031 dt_opencl_release_mem_object(dev_blurmat);
1032 if(err != CL_SUCCESS) goto error;
1033 }
1034 else
1035 {
1036 dt_opencl_release_mem_object(dev_blurmat);
1037 goto error;
1038 }
1039 }
1040
1041 {
1042 size_t sizes[3] = { ROUNDUPDWD(iwidth, devid), ROUNDUPDHT(iheight, devid), 1 };
1044 dt_opencl_set_kernel_arg(devid, kernel, 0, sizeof(cl_mem), &out);
1045 dt_opencl_set_kernel_arg(devid, kernel, 1, sizeof(cl_mem), &tmp);
1046 dt_opencl_set_kernel_arg(devid, kernel, 2, sizeof(int), &iwidth);
1047 dt_opencl_set_kernel_arg(devid, kernel, 3, sizeof(int), &iheight);
1048 const int err = dt_opencl_enqueue_kernel_2d(devid, kernel, sizes);
1049 if(err != CL_SUCCESS) goto error;
1050 }
1051
1052 {
1053 const int err = dt_opencl_read_host_from_device(devid, lum, tmp, iwidth, iheight, sizeof(float));
1054 if(err != CL_SUCCESS) goto error;
1055 }
1056
1060 tmp = blur = out = NULL;
1061
1062 // here we have the slightly blurred full detail available
1063 float *warp_mask = dt_dev_distort_detail_mask(p, lum, self);
1064 if(IS_NULL_PTR(warp_mask)) goto error;
1065 // dt_dev_distort_detail_mask() may return `lum` unchanged when no geometric distortion is needed.
1066 const gboolean warp_mask_aliases_lum = (warp_mask == lum);
1067 if(!warp_mask_aliases_lum)
1068 {
1070 lum = NULL;
1071 }
1072
1073 const int msize = owidth * oheight;
1074 __OMP_PARALLEL_FOR_SIMD__(aligned(mask, warp_mask : 64))
1075 for(int idx = 0; idx < msize; idx++)
1076 {
1077 mask[idx] = mask[idx] * warp_mask[idx];
1078 }
1080 if(warp_mask_aliases_lum) lum = NULL;
1081 return;
1082
1083 error:
1084 dt_control_log(_("detail mask CL blending problem"));
1089}
1090
1091static inline void _blend_process_cl_exchange(cl_mem *a, cl_mem *b)
1092{
1093 cl_mem tmp = *a;
1094 *a = *b;
1095 *b = tmp;
1096}
1097
1099 const struct dt_dev_pixelpipe_iop_t *piece, cl_mem dev_in, cl_mem dev_out)
1100{
1101 const dt_iop_roi_t *const roi_in = &piece->roi_in;
1102 const dt_iop_roi_t *const roi_out = &piece->roi_out;
1103 if(pipe->bypass_blendif && self->dev->gui_attached && (self == self->dev->gui_module)) return 0;
1104
1106 if(IS_NULL_PTR(d)) return 0;
1107
1108 gboolean top_enabled = FALSE;
1109 gboolean raster_used = FALSE;
1110 gboolean drawn_used = FALSE;
1111 gboolean parametric_used = FALSE;
1112 dt_develop_blend_get_mask_usage(self, d, &top_enabled, &raster_used, &drawn_used, &parametric_used);
1113 if(!top_enabled) return 0;
1114 const unsigned int mask_mode = d->mask_mode;
1115 // A mask preview request must also be honored when every sub-mask is neutral.
1116 // In that case no raster/drawn/parametric mask is "used", but the effective
1117 // blend mask is still the uniform opacity mask written into alpha below.
1118 const gboolean preview_mask_mode = top_enabled;
1119
1120 const int ch = piece->dsc_in.channels; // the number of channels in the buffer
1121 const int xoffs = roi_out->x - roi_in->x;
1122 const int yoffs = roi_out->y - roi_in->y;
1123 const int iwidth = roi_in->width;
1124 const int iheight = roi_in->height;
1125 const int owidth = roi_out->width;
1126 const int oheight = roi_out->height;
1127 const size_t buffsize = (size_t)owidth * oheight;
1128 const float iscale = roi_in->scale;
1129 const float oscale = roi_out->scale;
1130 const gboolean rois_equal = iwidth == owidth || iheight == oheight || xoffs == 0 || yoffs == 0;
1131
1132 // In most cases of blending-enabled modules input and output of the module have
1133 // the exact same dimensions. Only in very special cases we allow a module's input
1134 // to exceed its output. This is namely the case for the spot removal module where
1135 // the source of a patch might lie outside the roi of the output image. Therefore:
1136 // We can only handle blending if roi_out and roi_in have the same scale and
1137 // if roi_out fits into the area given by roi_in. xoffs and yoffs describe the relative
1138 // offset of the input image to the output image. */
1139 if(oscale != iscale || xoffs < 0 || yoffs < 0
1140 || ((xoffs > 0 || yoffs > 0) && (owidth + xoffs > iwidth || oheight + yoffs > iheight)))
1141 {
1142 dt_control_log(_("skipped blending in module '%s': roi's do not match"), self->op);
1143 return 0;
1144 }
1145
1146 // only non-zero if mask_display was set by an _earlier_ module
1147 const dt_dev_pixelpipe_display_mask_t mask_display = pipe->mask_display;
1148
1149 // does user want us to display a specific channel?
1150 const dt_dev_pixelpipe_display_mask_t request_mask_display
1151 = (self->dev->gui_attached && (self == self->dev->gui_module) && (pipe == self->dev->pipe)
1152 && preview_mask_mode)
1153 ? self->request_mask_display
1155
1156 // get channel max values depending on colorspace
1157 const dt_develop_blend_colorspace_t blend_csp = d->blend_cst;
1159
1160 // obtaining the list of mask operations to perform
1161 _develop_mask_post_processing post_operations[3];
1162 const size_t post_operations_size = _develop_mask_get_post_operations(d, piece, post_operations);
1163
1164 // get the clipped opacity value 0 - 1
1165 const float opacity = fminf(fmaxf(d->opacity / 100.0f, 0.0f), 1.0f);
1166 const gboolean use_masks = raster_used || drawn_used || parametric_used;
1167 const gboolean raster_only = raster_used && !drawn_used && !parametric_used;
1168
1169 // allocate space for blend mask
1170 float *_mask = dt_pixelpipe_cache_alloc_align_float(buffsize, pipe);
1171 if(IS_NULL_PTR(_mask))
1172 {
1173 dt_control_log(_("could not allocate buffer for blending"));
1174 return 1;
1175 }
1176 float *const mask = _mask;
1177
1178 // setup some kernels
1179 int kernel_mask;
1180 int kernel;
1181 switch(blend_csp)
1182 {
1186 break;
1187
1191 break;
1192
1196 break;
1197
1199 default:
1202 break;
1203 }
1204 int kernel_mask_tone_curve = darktable.opencl->blendop->kernel_blendop_mask_tone_curve;
1205 int kernel_set_mask = darktable.opencl->blendop->kernel_blendop_set_mask;
1206 int kernel_display_channel = darktable.opencl->blendop->kernel_blendop_display_channel;
1207
1208 const int devid = pipe->devid;
1209 const int offs[2] = { xoffs, yoffs };
1210 const size_t sizes[] = { ROUNDUPDWD(owidth, devid), ROUNDUPDHT(oheight, devid), 1 };
1211
1212 cl_int err = -999;
1213 cl_mem dev_blendif_params = NULL;
1214 cl_mem dev_boost_factors = NULL;
1215 cl_mem dev_mask_1 = NULL;
1216 cl_mem dev_mask_2 = NULL;
1217 cl_mem dev_tmp = NULL;
1218 cl_mem dev_guide = NULL;
1219
1220 cl_mem dev_profile_info = NULL;
1221 cl_mem dev_profile_lut = NULL;
1222 dt_colorspaces_iccprofile_info_cl_t *profile_info_cl = NULL;
1223 cl_float *profile_lut_cl = NULL;
1224
1225 cl_mem dev_work_profile_info = NULL;
1226 cl_mem dev_work_profile_lut = NULL;
1227 dt_colorspaces_iccprofile_info_cl_t *work_profile_info_cl = NULL;
1228 cl_float *work_profile_lut_cl = NULL;
1229
1230 size_t origin[] = { 0, 0, 0 };
1231 size_t region[] = { owidth, oheight, 1 };
1232
1233 // parameters, for every channel the 4 limits + pre-computed increasing slope and decreasing slope
1236
1237 // copy blend parameters to constant device memory
1238 dev_blendif_params = dt_opencl_copy_host_to_device_constant(devid, sizeof(parameters), parameters);
1239 if(IS_NULL_PTR(dev_blendif_params)) goto error;
1240
1241 dev_mask_1 = dt_opencl_alloc_device(devid, owidth, oheight, sizeof(float));
1242 if(IS_NULL_PTR(dev_mask_1)) goto error;
1243
1245 const int use_profile = dt_develop_blendif_init_masking_profile(pipe, piece, &profile, blend_csp);
1246
1247 err = dt_ioppr_build_iccprofile_params_cl(use_profile ? &profile : NULL, devid, &profile_info_cl,
1248 &profile_lut_cl, &dev_profile_info, &dev_profile_lut);
1249 if(err != CL_SUCCESS) goto error;
1250
1251 if(!use_masks)
1252 {
1253 // blend uniformly (no drawn or parametric mask)
1254
1255 // set dev_mask with global opacity value
1256 dt_opencl_set_kernel_arg(devid, kernel_set_mask, 0, sizeof(cl_mem), (void *)&dev_mask_1);
1257 dt_opencl_set_kernel_arg(devid, kernel_set_mask, 1, sizeof(int), (void *)&owidth);
1258 dt_opencl_set_kernel_arg(devid, kernel_set_mask, 2, sizeof(int), (void *)&oheight);
1259 dt_opencl_set_kernel_arg(devid, kernel_set_mask, 3, sizeof(float), (void *)&opacity);
1260 err = dt_opencl_enqueue_kernel_2d(devid, kernel_set_mask, sizes);
1261 if(err != CL_SUCCESS) goto error;
1262 }
1263 else if(raster_only)
1264 {
1265 int raster_error = 0;
1266 _develop_blend_init_raster_mask(d, self, pipe, piece, mask, owidth, oheight, &raster_error);
1267 if(raster_error) goto error;
1268 dt_iop_image_mul_const(mask, opacity, owidth, oheight, 1);
1269
1270 err = dt_opencl_write_host_to_device(devid, mask, dev_mask_1, owidth, oheight, sizeof(float));
1271 if(err != CL_SUCCESS) goto error;
1272 }
1273 else
1274 {
1275 if(!raster_used && !drawn_used)
1276 {
1277 // Parametric-only blending has no raster/drawn form mask to seed `mask`.
1278 // The OpenCL mask kernel reads that form mask from `dev_mask_1`, so keep
1279 // the CPU staging buffer explicit and initialized before upload.
1280 const float fill = (d->mask_combine & DEVELOP_COMBINE_INCL) ? 0.0f : 1.0f;
1281 dt_iop_image_fill(mask, fill, owidth, oheight, 1);
1282 }
1283 else if(raster_used)
1284 {
1285 int raster_error = 0;
1286 _develop_blend_init_raster_mask(d, self, pipe, piece, mask, owidth, oheight, &raster_error);
1287 if(raster_error) goto error;
1288
1289 if(drawn_used)
1290 {
1291 float *const restrict drawn_mask = dt_pixelpipe_cache_alloc_align_float(buffsize, pipe);
1292 if(IS_NULL_PTR(drawn_mask)) goto error;
1293
1294 if(_develop_blend_init_drawn_mask(d, self, pipe, piece, roi_out, drawn_mask, owidth, oheight) != 0)
1295 {
1297 goto error;
1298 }
1299
1300 _develop_blend_combine_masks(mask, drawn_mask, buffsize);
1302 }
1303 }
1304 else if(drawn_used
1305 && _develop_blend_init_drawn_mask(d, self, pipe, piece, roi_out, mask, owidth, oheight) != 0)
1306 {
1307 goto error;
1308 }
1309 _refine_with_detail_mask_cl(self, pipe, piece, mask, d->details, devid);
1310
1311 // write mask from host to device
1312 dev_mask_2 = dt_opencl_alloc_device(devid, owidth, oheight, sizeof(float));
1313 if(IS_NULL_PTR(dev_mask_2)) goto error;
1314 err = dt_opencl_write_host_to_device(devid, mask, dev_mask_1, owidth, oheight, sizeof(float));
1315 if(err != CL_SUCCESS) goto error;
1316
1317 // get parametric mask (if any) and apply global opacity
1318 const unsigned blendif = d->blendif;
1319 const unsigned int mask_combine = d->mask_combine;
1320 dt_opencl_set_kernel_arg(devid, kernel_mask, 0, sizeof(cl_mem), (void *)&dev_in);
1321 dt_opencl_set_kernel_arg(devid, kernel_mask, 1, sizeof(cl_mem), (void *)&dev_out);
1322 dt_opencl_set_kernel_arg(devid, kernel_mask, 2, sizeof(cl_mem), (void *)&dev_mask_1);
1323 dt_opencl_set_kernel_arg(devid, kernel_mask, 3, sizeof(cl_mem), (void *)&dev_mask_2);
1324 dt_opencl_set_kernel_arg(devid, kernel_mask, 4, sizeof(int), (void *)&owidth);
1325 dt_opencl_set_kernel_arg(devid, kernel_mask, 5, sizeof(int), (void *)&oheight);
1326 dt_opencl_set_kernel_arg(devid, kernel_mask, 6, sizeof(float), (void *)&opacity);
1327 dt_opencl_set_kernel_arg(devid, kernel_mask, 7, sizeof(unsigned), (void *)&blendif);
1328 dt_opencl_set_kernel_arg(devid, kernel_mask, 8, sizeof(cl_mem), (void *)&dev_blendif_params);
1329 dt_opencl_set_kernel_arg(devid, kernel_mask, 9, sizeof(unsigned), (void *)&mask_mode);
1330 dt_opencl_set_kernel_arg(devid, kernel_mask, 10, sizeof(unsigned), (void *)&mask_combine);
1331 dt_opencl_set_kernel_arg(devid, kernel_mask, 11, 2 * sizeof(int), (void *)&offs);
1332 dt_opencl_set_kernel_arg(devid, kernel_mask, 12, sizeof(cl_mem), (void *)&dev_profile_info);
1333 dt_opencl_set_kernel_arg(devid, kernel_mask, 13, sizeof(cl_mem), (void *)&dev_profile_lut);
1334 dt_opencl_set_kernel_arg(devid, kernel_mask, 14, sizeof(int), (void *)&use_profile);
1335 err = dt_opencl_enqueue_kernel_2d(devid, kernel_mask, sizes);
1336 if(err != CL_SUCCESS)
1337 {
1338 fprintf(stderr, "[dt_develop_blend_process_cl] error %i enqueue kernel\n", err);
1339 goto error;
1340 }
1341
1342 // the mask is now located in dev_mask_2, put it in dev_mask_1
1343 _blend_process_cl_exchange(&dev_mask_1, &dev_mask_2);
1344
1345 // post processing the mask (it will always be stored in dev_mask_1)
1346 for(size_t index = 0; index < post_operations_size; ++index)
1347 {
1348 _develop_mask_post_processing operation = post_operations[index];
1349 if(operation == DEVELOP_MASK_POST_FEATHER_IN)
1350 {
1351 int w = (int)(2 * d->feathering_radius * roi_out->scale + 0.5f);
1352 if (w < 1) w = 1;
1353 const float sqrt_eps = 1.0f;
1354 const float guide_weight = dt_iop_colorspace_is_rgb(cst) ? 100.0f : 1.0f;
1355
1356 cl_mem guide = dev_in;
1357 if(!rois_equal)
1358 {
1359 dev_guide = dt_opencl_alloc_device(devid, owidth, oheight, sizeof(float) * 4);
1360 if(IS_NULL_PTR(dev_guide)) goto error;
1361 guide = dev_guide;
1362 size_t origin_1[] = { xoffs, yoffs, 0 };
1363 size_t origin_2[] = { 0, 0, 0 };
1364 err = dt_opencl_enqueue_copy_image(devid, dev_in, guide, origin_2, origin_1, region);
1365 if(err != CL_SUCCESS) goto error;
1366 }
1367 if(guided_filter_cl(devid, guide, dev_mask_1, dev_mask_2, owidth, oheight, ch, w, sqrt_eps, guide_weight,
1368 0.0f, 1.0f) != 0)
1369 goto error;
1370 if(!rois_equal)
1371 {
1373 dev_guide = NULL;
1374 }
1375 _blend_process_cl_exchange(&dev_mask_1, &dev_mask_2);
1376 }
1377 else if(operation == DEVELOP_MASK_POST_FEATHER_OUT)
1378 {
1379 int w = (int)(2 * d->feathering_radius * roi_out->scale + 0.5f);
1380 if (w < 1) w = 1;
1381 const float sqrt_eps = 1.0f;
1382 const float guide_weight = dt_iop_colorspace_is_rgb(cst) ? 100.0f : 1.0f;
1383
1384 if(guided_filter_cl(devid, dev_out, dev_mask_1, dev_mask_2, owidth, oheight, ch, w, sqrt_eps, guide_weight,
1385 0.0f, 1.0f) != 0)
1386 goto error;
1387 _blend_process_cl_exchange(&dev_mask_1, &dev_mask_2);
1388 }
1389 else if(operation == DEVELOP_MASK_POST_BLUR)
1390 {
1391 const float sigma = d->blur_radius * roi_out->scale;
1392 const float mmax[] = { 1.0f };
1393 const float mmin[] = { 0.0f };
1394
1395 dt_gaussian_cl_t *g = dt_gaussian_init_cl(devid, owidth, oheight, 1, mmax, mmin, sigma, 0);
1396 if(IS_NULL_PTR(g)) goto error;
1397 err = dt_gaussian_blur_cl(g, dev_mask_1, dev_mask_2);
1399 if(err != CL_SUCCESS) goto error;
1400 _blend_process_cl_exchange(&dev_mask_1, &dev_mask_2);
1401 }
1402 else if(operation == DEVELOP_MASK_POST_TONE_CURVE)
1403 {
1404 const float e = expf(3.f * d->contrast);
1405 const float brightness = d->brightness;
1406 dt_opencl_set_kernel_arg(devid, kernel_mask_tone_curve, 0, sizeof(cl_mem), (void *)&dev_mask_1);
1407 dt_opencl_set_kernel_arg(devid, kernel_mask_tone_curve, 1, sizeof(cl_mem), (void *)&dev_mask_2);
1408 dt_opencl_set_kernel_arg(devid, kernel_mask_tone_curve, 2, sizeof(int), (void *)&owidth);
1409 dt_opencl_set_kernel_arg(devid, kernel_mask_tone_curve, 3, sizeof(int), (void *)&oheight);
1410 dt_opencl_set_kernel_arg(devid, kernel_mask_tone_curve, 4, sizeof(float), (void *)&e);
1411 dt_opencl_set_kernel_arg(devid, kernel_mask_tone_curve, 5, sizeof(float), (void *)&brightness);
1412 dt_opencl_set_kernel_arg(devid, kernel_mask_tone_curve, 6, sizeof(float), (void *)&opacity);
1413 err = dt_opencl_enqueue_kernel_2d(devid, kernel_mask_tone_curve, sizes);
1414 if(err != CL_SUCCESS) goto error;
1415 _blend_process_cl_exchange(&dev_mask_1, &dev_mask_2);
1416 }
1417 }
1418
1419 // get rid of dev_mask_2
1420 dt_opencl_release_mem_object(dev_mask_2);
1421 dev_mask_2 = NULL;
1422 }
1423
1424 // get temporary buffer for output image to overcome readonly/writeonly limitation
1425 dev_tmp = dt_opencl_alloc_device(devid, owidth, oheight, sizeof(float) * 4);
1426 if(IS_NULL_PTR(dev_tmp)) goto error;
1427
1428 err = dt_opencl_enqueue_copy_image(devid, dev_out, dev_tmp, origin, origin, region);
1429 if(err != CL_SUCCESS) goto error;
1430
1431 if(request_mask_display & DT_DEV_PIXELPIPE_DISPLAY_ANY)
1432 {
1433 // load the boost factors in the device memory
1434 dev_boost_factors = dt_opencl_copy_host_to_device_constant(devid, sizeof(d->blendif_boost_factors),
1435 d->blendif_boost_factors);
1436 if(IS_NULL_PTR(dev_boost_factors)) goto error;
1437
1438 // the display channel of Lab blending is generated in RGB and should be transformed to Lab
1439 // the transformation in the pipeline is currently always using the work profile
1441 const int use_work_profile = !IS_NULL_PTR(work_profile);
1442
1443 err = dt_ioppr_build_iccprofile_params_cl(work_profile, devid, &work_profile_info_cl, &work_profile_lut_cl,
1444 &dev_work_profile_info, &dev_work_profile_lut);
1445 if(err != CL_SUCCESS) goto error;
1446
1447 // let us display a specific channel
1448 dt_opencl_set_kernel_arg(devid, kernel_display_channel, 0, sizeof(cl_mem), (void *)&dev_in);
1449 dt_opencl_set_kernel_arg(devid, kernel_display_channel, 1, sizeof(cl_mem), (void *)&dev_tmp);
1450 dt_opencl_set_kernel_arg(devid, kernel_display_channel, 2, sizeof(cl_mem), (void *)&dev_mask_1);
1451 dt_opencl_set_kernel_arg(devid, kernel_display_channel, 3, sizeof(cl_mem), (void *)&dev_out);
1452 dt_opencl_set_kernel_arg(devid, kernel_display_channel, 4, sizeof(int), (void *)&owidth);
1453 dt_opencl_set_kernel_arg(devid, kernel_display_channel, 5, sizeof(int), (void *)&oheight);
1454 dt_opencl_set_kernel_arg(devid, kernel_display_channel, 6, 2 * sizeof(int), (void *)&offs);
1455 dt_opencl_set_kernel_arg(devid, kernel_display_channel, 7, sizeof(int), (void *)&request_mask_display);
1456 dt_opencl_set_kernel_arg(devid, kernel_display_channel, 8, sizeof(cl_mem), (void*)&dev_boost_factors);
1457 dt_opencl_set_kernel_arg(devid, kernel_display_channel, 9, sizeof(cl_mem), (void *)&dev_profile_info);
1458 dt_opencl_set_kernel_arg(devid, kernel_display_channel, 10, sizeof(cl_mem), (void *)&dev_profile_lut);
1459 dt_opencl_set_kernel_arg(devid, kernel_display_channel, 11, sizeof(int), (void *)&use_profile);
1460 dt_opencl_set_kernel_arg(devid, kernel_display_channel, 12, sizeof(cl_mem), (void *)&dev_work_profile_info);
1461 dt_opencl_set_kernel_arg(devid, kernel_display_channel, 13, sizeof(cl_mem), (void *)&dev_work_profile_lut);
1462 dt_opencl_set_kernel_arg(devid, kernel_display_channel, 14, sizeof(int), (void *)&use_work_profile);
1463 err = dt_opencl_enqueue_kernel_2d(devid, kernel_display_channel, sizes);
1464 if(err != CL_SUCCESS)
1465 {
1466 fprintf(stderr, "[dt_develop_blend_process_cl] error %i enqueue kernel\n", err);
1467 goto error;
1468 }
1469 }
1470 else
1471 {
1472 // apply blending with per-pixel opacity value as defined in dev_mask_1
1473 const unsigned int blend_mode = d->blend_mode;
1474 const float blend_parameter = exp2f(d->blend_parameter);
1475 dt_opencl_set_kernel_arg(devid, kernel, 0, sizeof(cl_mem), (void *)&dev_in);
1476 dt_opencl_set_kernel_arg(devid, kernel, 1, sizeof(cl_mem), (void *)&dev_tmp);
1477 dt_opencl_set_kernel_arg(devid, kernel, 2, sizeof(cl_mem), (void *)&dev_mask_1);
1478 dt_opencl_set_kernel_arg(devid, kernel, 3, sizeof(cl_mem), (void *)&dev_out);
1479 dt_opencl_set_kernel_arg(devid, kernel, 4, sizeof(int), (void *)&owidth);
1480 dt_opencl_set_kernel_arg(devid, kernel, 5, sizeof(int), (void *)&oheight);
1481 dt_opencl_set_kernel_arg(devid, kernel, 6, sizeof(unsigned), (void *)&blend_mode);
1482 dt_opencl_set_kernel_arg(devid, kernel, 7, sizeof(float), (void *)&blend_parameter);
1483 dt_opencl_set_kernel_arg(devid, kernel, 8, 2 * sizeof(int), (void *)&offs);
1484 dt_opencl_set_kernel_arg(devid, kernel, 9, sizeof(int), (void *)&mask_display);
1485 err = dt_opencl_enqueue_kernel_2d(devid, kernel, sizes);
1486 if(err != CL_SUCCESS) goto error;
1487 }
1488
1489 // register if _this_ module should expose mask or display channel
1491 {
1492 pipe->mask_display = request_mask_display;
1493 }
1494
1495
1496 // check if we should store the mask for export or use in subsequent modules
1498 {
1499 // get back final mask from the device to store it for later use
1500 if(!raster_only)
1501 {
1502 err = dt_opencl_copy_device_to_host(devid, mask, dev_mask_1, owidth, oheight, sizeof(float));
1503 if(err != CL_SUCCESS) goto error;
1504 }
1505
1506 const uint64_t mask_hash = dt_dev_pixelpipe_raster_mask_hash(piece, 0);
1507 dt_pixel_cache_entry_t *mask_entry = NULL;
1508 void *cache_data = NULL;
1509 const int created = dt_dev_pixelpipe_cache_get(
1510 darktable.pixelpipe_cache, mask_hash, sizeof(float) * buffsize,
1511 "raster mask", pipe->type, TRUE, &cache_data, &mask_entry);
1512
1513 if(IS_NULL_PTR(cache_data) || IS_NULL_PTR(mask_entry))
1514 {
1515 if(created && !IS_NULL_PTR(mask_entry))
1517 if(!IS_NULL_PTR(mask_entry))
1518 {
1520 if(created)
1522 }
1523 goto error;
1524 }
1525
1526 // The OpenCL mask has been materialized into `_mask` above. Publish that
1527 // host payload once so CPU and GPU consumers share the same cache entry.
1528 if(created)
1529 {
1530 memcpy(cache_data, _mask, sizeof(float) * buffsize);
1532 }
1533 // Transfer cache_get()'s reference to the pipe. It keeps this side-band
1534 // output alive until the next graph state is prepared or the pipe closes.
1535 g_array_append_val(pipe->raster_mask_hashes, mask_hash);
1537 _mask = NULL;
1538
1539 if(created && dt_supervisor_active())
1541 dt_supervisor_node_key(pipe->type, piece->module->op,
1542 piece->module->multi_priority),
1543 piece->hash, piece->global_hash, piece->module->op,
1544 piece->module->multi_priority, piece->module->iop_order,
1545 pipe->type, pipe->imgid, piece->roi_out.width,
1546 piece->roi_out.height, devid, sizeof(float) * buffsize,
1547 "raster mask");
1548
1550 "[raster masks] %s mask id 0 for module %s (%s) for pipe %s"
1551 " with cache hash %" PRIu64 "\n",
1552 created ? "published" : "reused cached",
1553 piece->module->op, piece->module->multi_name,
1554 dt_pipe_type_to_str(pipe->type), mask_hash);
1555 }
1556 else
1557 {
1559 "[raster masks] discarding unpublished mask id 0 for module %s (%s) for pipe %s\n",
1560 piece->module->op, piece->module->multi_name,
1561 dt_pipe_type_to_str(pipe->type));
1563 }
1564
1565 dt_opencl_release_mem_object(dev_blendif_params);
1566 dt_opencl_release_mem_object(dev_boost_factors);
1567 dt_opencl_release_mem_object(dev_mask_1);
1569 dt_ioppr_free_iccprofile_params_cl(&profile_info_cl, &profile_lut_cl, &dev_profile_info, &dev_profile_lut);
1570 dt_ioppr_free_iccprofile_params_cl(&work_profile_info_cl, &work_profile_lut_cl, &dev_work_profile_info,
1571 &dev_work_profile_lut);
1572 return 0;
1573
1574error:
1576 dt_opencl_release_mem_object(dev_blendif_params);
1577 dt_opencl_release_mem_object(dev_boost_factors);
1578 dt_opencl_release_mem_object(dev_mask_1);
1579 dt_opencl_release_mem_object(dev_mask_2);
1582 if(profile_info_cl) dt_ioppr_free_iccprofile_params_cl(&profile_info_cl, &profile_lut_cl, &dev_profile_info, &dev_profile_lut);
1583 if(work_profile_info_cl) dt_ioppr_free_iccprofile_params_cl(&work_profile_info_cl, &work_profile_lut_cl, &dev_work_profile_info,
1584 &dev_work_profile_lut);
1585 dt_print(DT_DEBUG_OPENCL, "[opencl_blendop] couldn't enqueue kernel! %d\n", err);
1586 return 1;
1587}
1588#endif
1589
1592{
1593#ifdef HAVE_OPENCL
1595
1596 const int program = 3; // blendop.cl, from programs.conf
1597 b->kernel_blendop_mask_Lab = dt_opencl_create_kernel(program, "blendop_mask_Lab");
1598 b->kernel_blendop_mask_RAW = dt_opencl_create_kernel(program, "blendop_mask_RAW");
1599 b->kernel_blendop_mask_rgb_hsl = dt_opencl_create_kernel(program, "blendop_mask_rgb_hsl");
1600 b->kernel_blendop_mask_rgb_jzczhz = dt_opencl_create_kernel(program, "blendop_mask_rgb_jzczhz");
1601 b->kernel_blendop_Lab = dt_opencl_create_kernel(program, "blendop_Lab");
1602 b->kernel_blendop_RAW = dt_opencl_create_kernel(program, "blendop_RAW");
1603 b->kernel_blendop_rgb_hsl = dt_opencl_create_kernel(program, "blendop_rgb_hsl");
1604 b->kernel_blendop_rgb_jzczhz = dt_opencl_create_kernel(program, "blendop_rgb_jzczhz");
1605 b->kernel_blendop_mask_tone_curve = dt_opencl_create_kernel(program, "blendop_mask_tone_curve");
1606 b->kernel_blendop_set_mask = dt_opencl_create_kernel(program, "blendop_set_mask");
1607 b->kernel_blendop_display_channel = dt_opencl_create_kernel(program, "blendop_display_channel");
1608
1609 const int program_rcd = 31;
1610 b->kernel_calc_Y0_mask = dt_opencl_create_kernel(program_rcd, "calc_Y0_mask");
1611 b->kernel_calc_scharr_mask = dt_opencl_create_kernel(program_rcd, "calc_scharr_mask");
1612 b->kernel_write_mask = dt_opencl_create_kernel(program_rcd, "writeout_mask");
1613 b->kernel_read_mask = dt_opencl_create_kernel(program_rcd, "readin_mask");
1614 b->kernel_calc_blend = dt_opencl_create_kernel(program_rcd, "calc_detail_blend");
1615 b->kernel_mask_blur = dt_opencl_create_kernel(program_rcd, "fastblur_mask_9x9");
1616
1617 return b;
1618#else
1619 return NULL;
1620#endif
1621}
1622
1625{
1626#ifdef HAVE_OPENCL
1627 if(IS_NULL_PTR(b)) return;
1628
1629 dt_opencl_free_kernel(b->kernel_blendop_mask_Lab);
1630 dt_opencl_free_kernel(b->kernel_blendop_mask_RAW);
1631 dt_opencl_free_kernel(b->kernel_blendop_mask_rgb_hsl);
1632 dt_opencl_free_kernel(b->kernel_blendop_mask_rgb_jzczhz);
1633 dt_opencl_free_kernel(b->kernel_blendop_Lab);
1634 dt_opencl_free_kernel(b->kernel_blendop_RAW);
1635 dt_opencl_free_kernel(b->kernel_blendop_rgb_hsl);
1636 dt_opencl_free_kernel(b->kernel_blendop_rgb_jzczhz);
1637 dt_opencl_free_kernel(b->kernel_blendop_mask_tone_curve);
1638 dt_opencl_free_kernel(b->kernel_blendop_set_mask);
1639 dt_opencl_free_kernel(b->kernel_blendop_display_channel);
1640 dt_opencl_free_kernel(b->kernel_calc_Y0_mask);
1641 dt_opencl_free_kernel(b->kernel_calc_scharr_mask);
1642 dt_opencl_free_kernel(b->kernel_write_mask);
1643 dt_opencl_free_kernel(b->kernel_read_mask);
1644 dt_opencl_free_kernel(b->kernel_calc_blend);
1645 dt_opencl_free_kernel(b->kernel_mask_blur);
1646 dt_free(b);
1647#endif
1648}
1649
1652{
1653 return DEVELOP_BLEND_VERSION;
1654}
1655
1657void tiling_callback_blendop(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe,
1658 const struct dt_dev_pixelpipe_iop_t *piece, struct dt_develop_tiling_t *tiling)
1659{
1660 tiling->factor = 3.5f; // in + out + (guide, tmp) + two quarter buffers for the mask
1661 tiling->maxbuf = 1.0f;
1662 tiling->overhead = 0;
1663 tiling->overlap = 0;
1664 tiling->xalign = 1;
1665 tiling->yalign = 1;
1666
1668 if(!IS_NULL_PTR(bldata))
1669 {
1670 if(bldata->details != 0.0f)
1671 tiling->factor += 0.75f; // details mask requires 3 additional quarter buffers
1672 }
1673}
1674
1678gboolean dt_develop_blend_params_is_all_zero(const void *params, size_t length)
1679{
1680 const char *data = (const char *)params;
1681
1682 for(size_t k = 0; k < length; k++)
1683 if(data[k]) return FALSE;
1684
1685 return TRUE;
1686}
1687
1688static uint32_t _blend_legacy_blend_mode(uint32_t legacy_blend_mode)
1689{
1690 uint32_t blend_mode = legacy_blend_mode & DEVELOP_BLEND_MODE_MASK;
1691 gboolean blend_reverse = FALSE;
1692 switch(blend_mode) {
1694 blend_mode = DEVELOP_BLEND_BOUNDED;
1695 break;
1697 blend_mode = DEVELOP_BLEND_BOUNDED;
1698 blend_reverse = TRUE;
1699 break;
1702 blend_mode = DEVELOP_BLEND_NORMAL2;
1703 break;
1705 blend_mode = DEVELOP_BLEND_MULTIPLY;
1706 blend_reverse = TRUE;
1707 break;
1708 default:
1709 break;
1710 }
1711 return (blend_reverse ? DEVELOP_BLEND_REVERSE : 0) | blend_mode;
1712}
1713
1715int dt_develop_blend_legacy_params(dt_iop_module_t *module, const void *const old_params,
1716 const int old_version, void *new_params, const int new_version,
1717 const int length)
1718{
1719 // edits before version 10 default to a display referred workflow
1721
1722 dt_develop_blend_params_t default_display_blend_params;
1723 dt_develop_blend_init_blend_parameters(&default_display_blend_params, cst);
1724
1725 // first deal with all-zero parameter sets, regardless of version number.
1726 // these occurred in previous darktable versions when modules without blend support stored zero-initialized data
1727 // in history stack. that's no problem unless the module gets blend support later (e.g. module exposure).
1728 // remedy: we simply initialize with the current default blend params in this case.
1729 if(dt_develop_blend_params_is_all_zero(old_params, length))
1730 {
1732
1733 *n = default_display_blend_params;
1734 return 0;
1735 }
1736
1737 if(old_version == 1 && new_version == 11)
1738 {
1740 typedef struct dt_develop_blend_params1_t
1741 {
1742 uint32_t mode;
1743 float opacity;
1744 uint32_t mask_id;
1745 } dt_develop_blend_params1_t;
1746
1747 if(length != sizeof(dt_develop_blend_params1_t)) return 1;
1748
1749 dt_develop_blend_params1_t *o = (dt_develop_blend_params1_t *)old_params;
1751
1752 *n = default_display_blend_params; // start with a fresh copy of default parameters
1754 n->blend_mode = _blend_legacy_blend_mode(o->mode);
1755 n->opacity = o->opacity;
1756 n->mask_id = o->mask_id;
1757 return 0;
1758 }
1759
1760 if(old_version == 2 && new_version == 11)
1761 {
1763 typedef struct dt_develop_blend_params2_t
1764 {
1766 uint32_t mode;
1768 float opacity;
1770 uint32_t mask_id;
1772 uint32_t blendif;
1774 float blendif_parameters[4 * 8];
1775 } dt_develop_blend_params2_t;
1776
1777 if(length != sizeof(dt_develop_blend_params2_t)) return 1;
1778
1779 dt_develop_blend_params2_t *o = (dt_develop_blend_params2_t *)old_params;
1781
1782 *n = default_display_blend_params; // start with a fresh copy of default parameters
1784 n->mask_mode |= ((o->blendif & (1u << DEVELOP_BLENDIF_active)) && (n->mask_mode == DEVELOP_MASK_ENABLED))
1786 : 0;
1787 n->blend_mode = _blend_legacy_blend_mode(o->mode);
1788 n->opacity = o->opacity;
1789 n->mask_id = o->mask_id;
1790 n->blendif = o->blendif & 0xff; // only just in case: knock out all bits
1791 // which were undefined in version
1792 // 2; also switch off old "active" bit
1793 for(int i = 0; i < (4 * 8); i++) n->blendif_parameters[i] = o->blendif_parameters[i];
1794
1795 return 0;
1796 }
1797
1798 if(old_version == 3 && new_version == 11)
1799 {
1801 typedef struct dt_develop_blend_params3_t
1802 {
1804 uint32_t mode;
1806 float opacity;
1808 uint32_t mask_id;
1810 uint32_t blendif;
1812 float blendif_parameters[4 * DEVELOP_BLENDIF_SIZE];
1813 } dt_develop_blend_params3_t;
1814
1815 if(length != sizeof(dt_develop_blend_params3_t)) return 1;
1816
1817 dt_develop_blend_params3_t *o = (dt_develop_blend_params3_t *)old_params;
1819
1820 *n = default_display_blend_params; // start with a fresh copy of default parameters
1822 n->mask_mode |= ((o->blendif & (1u << DEVELOP_BLENDIF_active)) && (n->mask_mode == DEVELOP_MASK_ENABLED))
1824 : 0;
1825 n->blend_mode = _blend_legacy_blend_mode(o->mode);
1826 n->opacity = o->opacity;
1827 n->mask_id = o->mask_id;
1828 n->blendif = o->blendif & ~(1u << DEVELOP_BLENDIF_active); // knock out old unused "active" flag
1829 memcpy(n->blendif_parameters, o->blendif_parameters, sizeof(float) * 4 * DEVELOP_BLENDIF_SIZE);
1830
1831 return 0;
1832 }
1833
1834 if(old_version == 4 && new_version == 11)
1835 {
1837 typedef struct dt_develop_blend_params4_t
1838 {
1840 uint32_t mode;
1842 float opacity;
1844 uint32_t mask_id;
1846 uint32_t blendif;
1848 float radius;
1850 float blendif_parameters[4 * DEVELOP_BLENDIF_SIZE];
1851 } dt_develop_blend_params4_t;
1852
1853 if(length != sizeof(dt_develop_blend_params4_t)) return 1;
1854
1855 dt_develop_blend_params4_t *o = (dt_develop_blend_params4_t *)old_params;
1857
1858 *n = default_display_blend_params; // start with a fresh copy of default parameters
1860 n->mask_mode |= ((o->blendif & (1u << DEVELOP_BLENDIF_active)) && (n->mask_mode == DEVELOP_MASK_ENABLED))
1862 : 0;
1863 n->blend_mode = _blend_legacy_blend_mode(o->mode);
1864 n->opacity = o->opacity;
1865 n->mask_id = o->mask_id;
1866 n->blur_radius = o->radius;
1867 n->blendif = o->blendif & ~(1u << DEVELOP_BLENDIF_active); // knock out old unused "active" flag
1868 memcpy(n->blendif_parameters, o->blendif_parameters, sizeof(float) * 4 * DEVELOP_BLENDIF_SIZE);
1869
1870 return 0;
1871 }
1872
1873 if(old_version == 5 && new_version == 11)
1874 {
1876 typedef struct dt_develop_blend_params5_t
1877 {
1879 uint32_t mask_mode;
1881 uint32_t blend_mode;
1883 float opacity;
1885 uint32_t mask_combine;
1887 uint32_t mask_id;
1889 uint32_t blendif;
1891 float radius;
1893 uint32_t reserved[4];
1895 float blendif_parameters[4 * DEVELOP_BLENDIF_SIZE];
1896 } dt_develop_blend_params5_t;
1897
1898 if(length != sizeof(dt_develop_blend_params5_t)) return 1;
1899
1900 dt_develop_blend_params5_t *o = (dt_develop_blend_params5_t *)old_params;
1902
1903 *n = default_display_blend_params; // start with a fresh copy of default parameters
1904 n->mask_mode = o->mask_mode;
1905 n->blend_mode = _blend_legacy_blend_mode(o->blend_mode);
1906 n->opacity = o->opacity;
1907 n->mask_combine = o->mask_combine;
1908 n->mask_id = o->mask_id;
1909 n->blur_radius = o->radius;
1910 // this is needed as version 5 contained a bug which screwed up history
1911 // stacks of even older
1912 // versions. potentially bad history stacks can be identified by an active
1913 // bit no. 32 in blendif.
1914 n->blendif = (o->blendif & (1u << DEVELOP_BLENDIF_active) ? o->blendif | 31 : o->blendif)
1915 & ~(1u << DEVELOP_BLENDIF_active);
1916 memcpy(n->blendif_parameters, o->blendif_parameters, sizeof(float) * 4 * DEVELOP_BLENDIF_SIZE);
1917
1918 return 0;
1919 }
1920
1921 if(old_version == 6 && new_version == 11)
1922 {
1924 typedef struct dt_develop_blend_params6_t
1925 {
1927 uint32_t mask_mode;
1929 uint32_t blend_mode;
1931 float opacity;
1933 uint32_t mask_combine;
1935 uint32_t mask_id;
1937 uint32_t blendif;
1939 float radius;
1941 uint32_t reserved[4];
1943 float blendif_parameters[4 * DEVELOP_BLENDIF_SIZE];
1944 } dt_develop_blend_params6_t;
1945
1946 if(length != sizeof(dt_develop_blend_params6_t)) return 1;
1947
1948 dt_develop_blend_params6_t *o = (dt_develop_blend_params6_t *)old_params;
1950
1951 *n = default_display_blend_params; // start with a fresh copy of default parameters
1952 n->mask_mode = o->mask_mode;
1953 n->blend_mode = _blend_legacy_blend_mode(o->blend_mode);
1954 n->opacity = o->opacity;
1955 n->mask_combine = o->mask_combine;
1956 n->mask_id = o->mask_id;
1957 n->blur_radius = o->radius;
1958 n->blendif = o->blendif;
1959 memcpy(n->blendif_parameters, o->blendif_parameters, sizeof(float) * 4 * DEVELOP_BLENDIF_SIZE);
1960 return 0;
1961 }
1962
1963 if(old_version == 7 && new_version == 11)
1964 {
1966 typedef struct dt_develop_blend_params7_t
1967 {
1969 uint32_t mask_mode;
1971 uint32_t blend_mode;
1973 float opacity;
1975 uint32_t mask_combine;
1977 uint32_t mask_id;
1979 uint32_t blendif;
1981 float radius;
1983 uint32_t reserved[4];
1985 float blendif_parameters[4 * DEVELOP_BLENDIF_SIZE];
1986 } dt_develop_blend_params7_t;
1987
1988 if(length != sizeof(dt_develop_blend_params7_t)) return 1;
1989
1990 dt_develop_blend_params7_t *o = (dt_develop_blend_params7_t *)old_params;
1992
1993 *n = default_display_blend_params; // start with a fresh copy of default parameters
1994 n->mask_mode = o->mask_mode;
1995 n->blend_mode = _blend_legacy_blend_mode(o->blend_mode);
1996 n->opacity = o->opacity;
1997 n->mask_combine = o->mask_combine;
1998 n->mask_id = o->mask_id;
1999 n->blur_radius = o->radius;
2000 n->blendif = o->blendif;
2001 memcpy(n->blendif_parameters, o->blendif_parameters, sizeof(float) * 4 * DEVELOP_BLENDIF_SIZE);
2002 return 0;
2003 }
2004
2005 if(old_version == 8 && new_version == 11)
2006 {
2008 typedef struct dt_develop_blend_params8_t
2009 {
2011 uint32_t mask_mode;
2013 uint32_t blend_mode;
2015 float opacity;
2017 uint32_t mask_combine;
2019 uint32_t mask_id;
2021 uint32_t blendif;
2023 float feathering_radius;
2025 uint32_t feathering_guide;
2027 float blur_radius;
2029 float contrast;
2031 float brightness;
2033 uint32_t reserved[4];
2035 float blendif_parameters[4 * DEVELOP_BLENDIF_SIZE];
2036 } dt_develop_blend_params8_t;
2037
2038 if(length != sizeof(dt_develop_blend_params8_t)) return 1;
2039
2040 dt_develop_blend_params8_t *o = (dt_develop_blend_params8_t *)old_params;
2042
2043 *n = default_display_blend_params; // start with a fresh copy of default parameters
2044 n->mask_mode = o->mask_mode;
2045 n->blend_mode = _blend_legacy_blend_mode(o->blend_mode);
2046 n->opacity = o->opacity;
2047 n->mask_combine = o->mask_combine;
2048 n->mask_id = o->mask_id;
2049 n->blendif = o->blendif;
2050 n->feathering_radius = o->feathering_radius;
2051 n->feathering_guide = o->feathering_guide;
2052 n->blur_radius = o->blur_radius;
2053 n->contrast = o->contrast;
2054 n->brightness = o->brightness;
2055 memcpy(n->blendif_parameters, o->blendif_parameters, sizeof(float) * 4 * DEVELOP_BLENDIF_SIZE);
2056 return 0;
2057 }
2058
2059 if(old_version == 9 && new_version == 11)
2060 {
2062 typedef struct dt_develop_blend_params9_t
2063 {
2066 uint32_t mask_mode;
2068 uint32_t blend_mode;
2070 float opacity;
2072 uint32_t mask_combine;
2074 uint32_t mask_id;
2076 uint32_t blendif;
2078 float feathering_radius;
2080 uint32_t feathering_guide;
2082 float blur_radius;
2084 float contrast;
2086 float brightness;
2088 uint32_t reserved[4];
2090 float blendif_parameters[4 * DEVELOP_BLENDIF_SIZE];
2091 dt_dev_operation_t raster_mask_source;
2092 int raster_mask_instance;
2093 int raster_mask_id;
2094 gboolean raster_mask_invert;
2095 } dt_develop_blend_params9_t;
2096
2097 if(length != sizeof(dt_develop_blend_params9_t)) return 1;
2098
2099 dt_develop_blend_params9_t *o = (dt_develop_blend_params9_t *)old_params;
2101
2102 *n = default_display_blend_params; // start with a fresh copy of default parameters
2103 n->mask_mode = o->mask_mode;
2104 n->blend_mode = _blend_legacy_blend_mode(o->blend_mode);
2105 n->opacity = o->opacity;
2106 n->mask_combine = o->mask_combine;
2107 n->mask_id = o->mask_id;
2108 n->blendif = o->blendif;
2109 n->feathering_radius = o->feathering_radius;
2110 n->feathering_guide = o->feathering_guide;
2111 n->blur_radius = o->blur_radius;
2112 n->contrast = o->contrast;
2113 n->brightness = o->brightness;
2114 memcpy(n->blendif_parameters, o->blendif_parameters, sizeof(float) * 4 * DEVELOP_BLENDIF_SIZE);
2115 memcpy(n->raster_mask_source, o->raster_mask_source, sizeof(n->raster_mask_source));
2116 n->raster_mask_instance = o->raster_mask_instance;
2117 n->raster_mask_id = o->raster_mask_id;
2118 n->raster_mask_invert = o->raster_mask_invert;
2119 return 0;
2120 }
2121
2122 if(old_version == 10 && new_version == 11)
2123 {
2125 typedef struct dt_develop_blend_params10_t
2126 {
2129 uint32_t mask_mode;
2131 int32_t blend_cst;
2133 uint32_t blend_mode;
2135 float blend_parameter;
2137 float opacity;
2139 uint32_t mask_combine;
2141 uint32_t mask_id;
2143 uint32_t blendif;
2145 float feathering_radius;
2147 uint32_t feathering_guide;
2149 float blur_radius;
2151 float contrast;
2153 float brightness;
2155 uint32_t reserved[4];
2157 float blendif_parameters[4 * DEVELOP_BLENDIF_SIZE];
2158 float blendif_boost_factors[DEVELOP_BLENDIF_SIZE];
2159 dt_dev_operation_t raster_mask_source;
2160 int raster_mask_instance;
2161 int raster_mask_id;
2162 gboolean raster_mask_invert;
2163 } dt_develop_blend_params10_t;
2164
2165 if(length != sizeof(dt_develop_blend_params10_t)) return 1;
2166
2167 dt_develop_blend_params10_t *o = (dt_develop_blend_params10_t *)old_params;
2169
2170 *n = default_display_blend_params; // start with a fresh copy of default parameters
2171 n->mask_mode = o->mask_mode;
2172 n->blend_cst = o->blend_cst;
2173 n->blend_mode = _blend_legacy_blend_mode(o->blend_mode);
2174 n->blend_parameter = o->blend_parameter;
2175 n->opacity = o->opacity;
2176 n->mask_combine = o->mask_combine;
2177 n->mask_id = o->mask_id;
2178 n->blendif = o->blendif;
2179 n->feathering_radius = o->feathering_radius;
2180 n->feathering_guide = o->feathering_guide;
2181 n->blur_radius = o->blur_radius;
2182 n->contrast = o->contrast;
2183 n->brightness = o->brightness;
2184 // fix intermediate devel versions for details mask and initialize n->details to proper values if something was wrong
2185 memcpy(&n->details, &o->reserved, sizeof(float));
2186 if(isnan(n->details)) n->details = 0.0f;
2187 n->details = fminf(1.0f, fmaxf(-1.0f, n->details));
2188
2189 memcpy(n->blendif_parameters, o->blendif_parameters, sizeof(float) * 4 * DEVELOP_BLENDIF_SIZE);
2190 memcpy(n->blendif_boost_factors, o->blendif_boost_factors, sizeof(float) * DEVELOP_BLENDIF_SIZE);
2191 memcpy(n->raster_mask_source, o->raster_mask_source, sizeof(n->raster_mask_source));
2192 n->raster_mask_instance = o->raster_mask_instance;
2193 n->raster_mask_id = o->raster_mask_id;
2194 n->raster_mask_invert = o->raster_mask_invert;
2195 return 0;
2196 }
2197
2198 return 1;
2199}
2200
2201int dt_develop_blend_legacy_params_from_so(dt_iop_module_so_t *module_so, const void *const old_params,
2202 const int old_version, void *new_params, const int new_version,
2203 const int length)
2204{
2205 // we need a dt_iop_module_t for dt_develop_blend_legacy_params()
2206 dt_iop_module_t *module = (dt_iop_module_t *)calloc(1, sizeof(dt_iop_module_t));
2207 if(dt_iop_load_module_by_so(module, module_so, NULL))
2208 {
2209 dt_free(module);
2210 return 1;
2211 }
2212
2213 if(module->params_size == 0)
2214 {
2215 dt_iop_cleanup_module(module);
2216 dt_free(module);
2217 return 1;
2218 }
2219
2220 // convert the old blend params to new
2221 const int res = dt_develop_blend_legacy_params(module, old_params, old_version,
2222 new_params, dt_develop_blend_version(),
2223 length);
2224 dt_iop_cleanup_module(module);
2225 dt_free(module);
2226 return res;
2227}
2228
2229// tools/update_modelines.sh
2230// remove-trailing-space on;
2231// clang-format off
2232// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
2233// vim: shiftwidth=2 expandtab tabstop=2 cindent
2234// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
2235// clang-format on
static void error(char *msg)
Definition ashift_lsd.c:202
#define TRUE
Definition ashift_lsd.c:162
#define FALSE
Definition ashift_lsd.c:158
int width
Definition bilateral.h:1
int height
Definition bilateral.h:1
static dt_develop_blend_colorspace_t _blend_default_module_blend_colorspace(dt_iop_module_t *module, gboolean is_scene_referred)
Definition blend.c:109
_develop_mask_post_processing
Definition blend.c:61
@ DEVELOP_MASK_POST_TONE_CURVE
Definition blend.c:66
@ DEVELOP_MASK_POST_FEATHER_IN
Definition blend.c:64
@ DEVELOP_MASK_POST_FEATHER_OUT
Definition blend.c:65
@ DEVELOP_MASK_POST_BLUR
Definition blend.c:63
@ DEVELOP_MASK_POST_NONE
Definition blend.c:62
void dt_develop_blend_init_blend_parameters(dt_develop_blend_params_t *blend_params, dt_develop_blend_colorspace_t cst)
Definition blend.c:158
static void _develop_blend_combine_masks(float *const restrict mask, const float *const restrict other_mask, const size_t buffsize)
Definition blend.c:578
int dt_develop_blend_process_cl(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, const struct dt_dev_pixelpipe_iop_t *piece, cl_mem dev_in, cl_mem dev_out)
Definition blend.c:1098
static void _develop_blend_init_raster_mask(const dt_develop_blend_params_t *const params, dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, float *const restrict mask, const size_t owidth, const size_t oheight, int *const raster_error)
Definition blend.c:506
static void _refine_with_detail_mask_cl(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe, const struct dt_dev_pixelpipe_iop_t *piece, float *mask, const float level, const int devid)
Definition blend.c:952
static size_t _develop_mask_get_post_operations(const dt_develop_blend_params_t *const params, const dt_dev_pixelpipe_iop_t *const piece, _develop_mask_post_processing operations[3])
Definition blend.c:412
static float * _develop_blend_process_copy_region(const float *const restrict input, const size_t iwidth, const size_t xoffs, const size_t yoffs, const size_t owidth, const size_t oheight)
Definition blend.c:456
void tiling_callback_blendop(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe, const struct dt_dev_pixelpipe_iop_t *piece, struct dt_develop_tiling_t *tiling)
Definition blend.c:1657
static uint32_t _blend_legacy_blend_mode(uint32_t legacy_blend_mode)
Definition blend.c:1688
dt_blendop_cl_global_t * dt_develop_blend_init_cl_global(void)
Definition blend.c:1591
void dt_develop_blendif_process_parameters(float *const restrict parameters, const dt_develop_blend_params_t *const params)
Definition blend.c:199
void dt_develop_blend_free_cl_global(dt_blendop_cl_global_t *b)
Definition blend.c:1624
dt_iop_colorspace_type_t dt_develop_blend_colorspace(const dt_dev_pixelpipe_iop_t *const piece, dt_iop_colorspace_type_t cst)
Definition blend.c:180
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:307
int dt_develop_blend_legacy_params_from_so(dt_iop_module_so_t *module_so, const void *const old_params, const int old_version, void *new_params, const int new_version, const int length)
Definition blend.c:2201
static void _refine_with_detail_mask(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe, const struct dt_dev_pixelpipe_iop_t *piece, float *mask, const float level)
Definition blend.c:346
dt_develop_blend_colorspace_t dt_develop_blend_default_module_blend_colorspace(dt_iop_module_t *module)
Definition blend.c:136
int dt_develop_blend_version(void)
Definition blend.c:1651
int dt_develop_blend_legacy_params(dt_iop_module_t *module, const void *const old_params, const int old_version, void *new_params, const int new_version, const int length)
Definition blend.c:1715
static const dt_iop_module_t * _develop_blend_get_raster_source_module(const dt_develop_blend_params_t *const params, const dt_iop_module_t *const self)
Definition blend.c:483
void dt_develop_blend_get_mask_usage(const dt_iop_module_t *module, const dt_develop_blend_params_t *params, gboolean *top_enabled, gboolean *raster_used, gboolean *drawn_used, gboolean *parametric_used)
Definition blend.c:247
int dt_develop_blend_process(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, const struct dt_dev_pixelpipe_iop_t *piece, const void *const ivoid, void *const ovoid)
Definition blend.c:642
static void _blend_init_blendif_boost_parameters(dt_develop_blend_params_t *blend_params, dt_develop_blend_colorspace_t cst)
Definition blend.c:141
static const char * dt_pipe_type_to_str(dt_dev_pixelpipe_type_t pipe_type)
Definition blend.c:69
gboolean dt_develop_blend_params_is_all_zero(const void *params, size_t length)
Definition blend.c:1678
static dt_develop_blend_params_t _default_blendop_params
Definition blend.c:87
static void _develop_blend_process_mask_tone_curve(float *const restrict mask, const size_t buffsize, const float contrast, const float brightness, const float opacity)
Definition blend.c:611
static void _develop_blend_process_free_region(float *const restrict input)
Definition blend.c:478
static float _detail_mask_threshold(const float level, const gboolean detail)
Definition blend.c:340
static int _develop_blend_init_drawn_mask(const dt_develop_blend_params_t *const params, dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, const struct dt_iop_roi_t *const roi_out, float *const restrict mask, const size_t owidth, const size_t oheight)
Definition blend.c:546
void dt_develop_blend_init_blendif_parameters(dt_develop_blend_params_t *blend_params, dt_develop_blend_colorspace_t cst)
Definition blend.c:166
static int _develop_blend_process_feather(const float *const guide, float *const mask, const size_t width, const size_t height, const int ch, const float guide_weight, const float feathering_radius, const float scale)
Definition blend.c:588
static void _blend_process_cl_exchange(cl_mem *a, cl_mem *b)
Definition blend.c:1091
void dt_develop_blendif_raw_blend(const struct dt_dev_pixelpipe_t *pipe, const struct dt_dev_pixelpipe_iop_t *piece, const float *const a, float *const b, const float *const mask, const dt_dev_pixelpipe_display_mask_t request_mask_display)
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 a, float *const b, const float *const mask, const dt_dev_pixelpipe_display_mask_t request_mask_display)
void dt_develop_blendif_rgb_hsl_make_mask(const struct dt_dev_pixelpipe_t *pipe, const struct dt_dev_pixelpipe_iop_t *piece, const float *const a, const float *const b, float *const mask)
@ DEVELOP_MASK_GUIDE_OUT_BEFORE_BLUR
Definition blend.h:138
@ DEVELOP_MASK_GUIDE_IN_AFTER_BLUR
Definition blend.h:139
@ DEVELOP_MASK_GUIDE_OUT_AFTER_BLUR
Definition blend.h:140
@ DEVELOP_MASK_GUIDE_IN_BEFORE_BLUR
Definition blend.h:137
dt_develop_blend_colorspace_t
Definition blend.h:55
@ DEVELOP_BLEND_CS_NONE
Definition blend.h:56
@ DEVELOP_BLEND_CS_LAB
Definition blend.h:58
@ DEVELOP_BLEND_CS_RGB_SCENE
Definition blend.h:60
@ DEVELOP_BLEND_CS_RGB_DISPLAY
Definition blend.h:59
@ DEVELOP_BLEND_CS_RAW
Definition blend.h:57
@ DEVELOP_COMBINE_INCL
Definition blend.h:127
@ DEVELOP_COMBINE_MASKS_POS
Definition blend.h:128
@ DEVELOP_COMBINE_NORM_EXCL
Definition blend.h:129
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 a, const float *const b, float *const mask)
void dt_develop_blendif_lab_blend(const struct dt_dev_pixelpipe_t *pipe, const struct dt_dev_pixelpipe_iop_t *piece, const float *const a, float *const b, const float *const mask, const dt_dev_pixelpipe_display_mask_t request_mask_display)
void dt_develop_blendif_raw_make_mask(const struct dt_dev_pixelpipe_iop_t *piece, const float *const a, const float *const b, float *const mask)
void dt_develop_blendif_rgb_hsl_blend(const struct dt_dev_pixelpipe_t *pipe, const struct dt_dev_pixelpipe_iop_t *piece, const float *const a, float *const b, const float *const mask, const dt_dev_pixelpipe_display_mask_t request_mask_display)
void dt_develop_blendif_lab_make_mask(const struct dt_dev_pixelpipe_iop_t *piece, const float *const a, const float *const b, float *const mask)
@ DEVELOP_BLENDIF_Cz_in
Definition blend.h:178
@ DEVELOP_BLENDIF_A_in
Definition blend.h:146
@ DEVELOP_BLENDIF_Lab_MASK
Definition blend.h:192
@ DEVELOP_BLENDIF_Jz_out
Definition blend.h:181
@ DEVELOP_BLENDIF_B_in
Definition blend.h:147
@ DEVELOP_BLENDIF_Cz_out
Definition blend.h:182
@ DEVELOP_BLENDIF_Jz_in
Definition blend.h:177
@ DEVELOP_BLENDIF_A_out
Definition blend.h:150
@ DEVELOP_BLENDIF_B_out
Definition blend.h:151
@ DEVELOP_BLENDIF_active
Definition blend.h:188
@ DEVELOP_BLENDIF_RGB_MASK
Definition blend.h:193
#define DEVELOP_BLENDIF_PARAMETER_ITEMS
Definition blend.h:452
@ DEVELOP_BLEND_BOUNDED
Definition blend.h:90
@ DEVELOP_BLEND_MODE_MASK
Definition blend.h:109
@ DEVELOP_BLEND_MULTIPLY_REVERSE_OBSOLETE
Definition blend.h:101
@ DEVELOP_BLEND_NORMAL2
Definition blend.h:89
@ DEVELOP_BLEND_REVERSE
Definition blend.h:108
@ DEVELOP_BLEND_DISABLED_OBSOLETE
Definition blend.h:65
@ DEVELOP_BLEND_MULTIPLY
Definition blend.h:69
@ DEVELOP_BLEND_NORMAL_OBSOLETE
Definition blend.h:66
@ DEVELOP_BLEND_UNBOUNDED_OBSOLETE
Definition blend.h:86
@ DEVELOP_BLEND_INVERSE_OBSOLETE
Definition blend.h:85
@ DEVELOP_MASK_RASTER
Definition blend.h:118
@ DEVELOP_MASK_PARAMETRIC
Definition blend.h:117
@ DEVELOP_MASK_DISABLED
Definition blend.h:114
@ DEVELOP_MASK_ENABLED
Definition blend.h:115
@ DEVELOP_MASK_SHAPE
Definition blend.h:116
#define DEVELOP_BLEND_VERSION
Definition blend.h:52
static const dt_aligned_pixel_simd_t const dt_adaptation_t const float p
dt_iop_colorspace_type_t
@ IOP_CS_RAW
@ IOP_CS_LCH
@ IOP_CS_JZCZHZ
@ IOP_CS_RGB
@ IOP_CS_HSL
@ IOP_CS_LAB
@ IOP_CS_NONE
const float threshold
const dt_colormatrix_t dt_aligned_pixel_t out
const float top
static const dt_colormatrix_t M
void dt_control_log(const char *msg,...)
Definition control.c:777
darktable_t darktable
Definition darktable.c:183
void dt_print(dt_debug_thread_t thread, const char *msg,...)
Definition darktable.c:1600
@ DT_DEBUG_OPENCL
Definition darktable.h:744
@ DT_DEBUG_MASKS
Definition darktable.h:749
#define DT_ALIGNED_ARRAY
Definition darktable.h:400
#define dt_pixelpipe_cache_alloc_align_float_cache(pixels, id)
Definition darktable.h:459
#define dt_free(ptr)
Definition darktable.h:478
#define dt_pixelpipe_cache_free_align(mem)
Definition darktable.h:475
#define dt_pixelpipe_cache_alloc_align_float(pixels, pipe)
Definition darktable.h:454
#define __OMP_PARALLEL_FOR__(...)
Definition darktable.h:270
static const dt_aligned_pixel_simd_t value
Definition darktable.h:599
#define __OMP_FOR_SIMD__(...)
Definition darktable.h:272
#define __OMP_PARALLEL_FOR_SIMD__(...)
Definition darktable.h:271
#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 darktable.h:293
dt_dev_pixelpipe_display_mask_t
Definition develop.h:116
@ DT_DEV_PIXELPIPE_DISPLAY_CHANNEL
Definition develop.h:119
@ DT_DEV_PIXELPIPE_DISPLAY_ANY
Definition develop.h:138
@ DT_DEV_PIXELPIPE_DISPLAY_MASK
Definition develop.h:118
@ DT_DEV_PIXELPIPE_DISPLAY_NONE
Definition develop.h:117
void dt_gaussian_free(dt_gaussian_t *g)
Definition gaussian.c:330
void dt_gaussian_free_cl(dt_gaussian_cl_t *g)
Definition gaussian.c:353
cl_int dt_gaussian_blur_cl(dt_gaussian_cl_t *g, cl_mem dev_in, cl_mem dev_out)
Definition gaussian.c:441
__DT_CLONE_TARGETS__ void dt_gaussian_blur(dt_gaussian_t *g, const float *const in, float *const out)
Definition gaussian.c:171
dt_gaussian_cl_t * dt_gaussian_init_cl(const int devid, const int width, const int height, const int channels, const float *max, const float *min, const float sigma, const int order)
Definition gaussian.c:364
dt_gaussian_t * dt_gaussian_init(const int width, const int height, const int channels, const float *max, const float *min, const float sigma, const int order)
Definition gaussian.c:122
int guided_filter_cl(int devid, cl_mem guide, cl_mem in, cl_mem out, const int width, const int height, const int ch, const int w, const float sqrt_eps, const float guide_weight, const float min, const float max)
__DT_CLONE_TARGETS__ int guided_filter(const float *const guide, const float *const in, float *const out, const int width, const int height, const int ch, const int w, const float sqrt_eps, const float guide_weight, const float min, const float max)
__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:351
__DT_CLONE_TARGETS__ void dt_iop_image_invert(float *const buf, const float max_value, const size_t width, const size_t height, const size_t ch)
Definition imagebuf.c:326
__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:214
__DT_CLONE_TARGETS__ void dt_iop_image_scaled_copy(float *const restrict buf, const float *const restrict src, const float scale, const size_t width, const size_t height, const size_t ch)
Definition imagebuf.c:189
gboolean dt_iop_is_raster_mask_used(dt_iop_module_t *module, int id)
Definition imageop.c:3146
void dt_iop_cleanup_module(dt_iop_module_t *module)
Definition imageop.c:1578
int dt_iop_load_module_by_so(dt_iop_module_t *module, dt_iop_module_so_t *so, dt_develop_t *dev)
Definition imageop.c:471
static gboolean dt_iop_colorspace_is_rgb(const dt_iop_colorspace_type_t cst)
Definition imageop.h:243
@ IOP_FLAGS_SUPPORTS_BLENDING
Definition imageop.h:197
@ IOP_FLAGS_NO_MASKS
Definition imageop.h:205
@ IOP_CS_RGB_DISPLAY
Definition imageop.h:240
void *const ovoid
static float kernel(const float *x, const float *y)
dt_iop_order_iccprofile_info_t * dt_ioppr_get_pipe_work_profile_info(const struct dt_dev_pixelpipe_t *pipe)
dt_iop_order_iccprofile_info_t * dt_ioppr_get_pipe_current_profile_info(dt_iop_module_t *module, const struct dt_dev_pixelpipe_t *pipe)
void dt_ioppr_free_iccprofile_params_cl(dt_colorspaces_iccprofile_info_cl_t **_profile_info_cl, cl_float **_profile_lut_cl, cl_mem *_dev_profile_info, cl_mem *_dev_profile_lut)
dt_iop_order_iccprofile_info_t * dt_ioppr_get_iop_work_profile_info(struct dt_iop_module_t *module, GList *iop_list)
cl_int dt_ioppr_build_iccprofile_params_cl(const dt_iop_order_iccprofile_info_t *const profile_info, const int devid, dt_colorspaces_iccprofile_info_cl_t **_profile_info_cl, cl_float **_profile_lut_cl, cl_mem *_dev_profile_info, cl_mem *_dev_profile_lut)
static const float x
#define DEVELOP_BLENDIF_SIZE
Definition lightroom.c:235
float *const restrict const size_t k
float *const restrict const size_t const size_t ch
int dt_masks_group_render_roi(dt_iop_module_t *module, dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, dt_masks_form_t *form, const dt_iop_roi_t *roi, float *buffer)
Definition group.c:663
void dt_masks_calc_detail_mask(float *const src, float *const out, float *const tmp, const int width, const int height, const float threshold, const gboolean detail)
void dt_masks_blur_9x9_coeff(float *coeffs, const float sigma)
Definition detail.c:159
@ DT_MASKS_GROUP
Definition masks.h:134
dt_masks_form_t * dt_masks_get_from_id(dt_develop_t *dev, int id)
static float clamp_range_f(const float x, const float low, const float high)
Definition math.h:96
float DT_ALIGNED_ARRAY dt_colormatrix_t[4][4]
Definition matrices.h:33
float iscale
Definition mipmap_cache.c:2
int dt_opencl_enqueue_kernel_2d(const int dev, const int kernel, const size_t *sizes)
Definition opencl.c:2164
void * dt_opencl_alloc_device_buffer(const int devid, const size_t size)
Definition opencl.c:2580
int dt_opencl_copy_device_to_host(const int devid, void *host, void *device, const int width, const int height, const int bpp)
Definition opencl.c:2191
void * dt_opencl_alloc_device(const int devid, const int width, const int height, const int bpp)
Definition opencl.c:2504
int dt_opencl_create_kernel(const int prog, const char *name)
Definition opencl.c:2058
void * dt_opencl_copy_host_to_device_constant(const int devid, const size_t size, void *host)
Definition opencl.c:2360
int dt_opencl_enqueue_copy_image(const int devid, cl_mem src, cl_mem dst, size_t *orig_src, size_t *orig_dst, size_t *region)
Definition opencl.c:2289
void dt_opencl_free_kernel(const int kernel)
Definition opencl.c:2101
int dt_opencl_set_kernel_arg(const int dev, const int kernel, const int num, const size_t size, const void *arg)
Definition opencl.c:2155
int dt_opencl_read_host_from_device(const int devid, void *host, void *device, const int width, const int height, const int bpp)
Definition opencl.c:2197
void dt_opencl_release_mem_object(cl_mem mem)
Definition opencl.c:2415
int dt_opencl_write_host_to_device(const int devid, void *host, void *device, const int width, const int height, const int bpp)
Definition opencl.c:2244
#define ROUNDUPDHT(a, b)
Definition opencl.h:82
#define ROUNDUPDWD(a, b)
Definition opencl.h:81
uint64_t dt_dev_pixelpipe_raster_mask_hash(const dt_dev_pixelpipe_iop_t *piece, const int raster_mask_id)
Definition pixelpipe.c:53
dt_dev_pixelpipe_type_t
Definition pixelpipe.h:36
@ DT_DEV_PIXELPIPE_THUMBNAIL
Definition pixelpipe.h:41
@ DT_DEV_PIXELPIPE_EXPORT
Definition pixelpipe.h:38
@ DT_DEV_PIXELPIPE_PREVIEW
Definition pixelpipe.h:40
@ DT_DEV_PIXELPIPE_FULL
Definition pixelpipe.h:39
void dt_dev_pixelpipe_cache_ref_count_entry(dt_dev_pixelpipe_cache_t *cache, gboolean lock, dt_pixel_cache_entry_t *cache_entry)
Increase/Decrease the reference count on the cache line as to prevent LRU item removal....
int dt_dev_pixelpipe_cache_get(dt_dev_pixelpipe_cache_t *cache, const uint64_t hash, const size_t size, const char *name, const int id, const gboolean alloc, void **data, dt_pixel_cache_entry_t **entry)
Get a cache line from the cache.
int dt_dev_pixelpipe_cache_remove(dt_dev_pixelpipe_cache_t *cache, const gboolean force, dt_pixel_cache_entry_t *cache_entry)
Arbitrarily remove the cache entry matching hash. Entries having a reference count > 0 (inter-thread ...
void dt_dev_pixelpipe_cache_wrlock_entry(dt_dev_pixelpipe_cache_t *cache, gboolean lock, dt_pixel_cache_entry_t *cache_entry)
Lock or release the write lock on the entry.
float * dt_dev_retrieve_rawdetail_mask(const dt_dev_pixelpipe_t *pipe, const struct dt_iop_module_t *target_module)
float * dt_dev_get_raster_mask(dt_dev_pixelpipe_t *pipe, const struct dt_iop_module_t *raster_mask_source, const int raster_mask_id, const struct dt_iop_module_t *target_module, int *error)
Retrieve a provider mask from the global cache and transform it to a consumer.
float * dt_dev_distort_detail_mask(const dt_dev_pixelpipe_t *pipe, float *src, const struct dt_iop_module_t *target_module)
char dt_dev_operation_t[20]
Definition settings.h:38
const float sigma
unsigned __int64 uint64_t
Definition strptime.c:75
struct dt_dev_pixelpipe_cache_t * pixelpipe_cache
Definition darktable.h:818
struct dt_opencl_t * opencl
Definition darktable.h:813
int32_t unmuted
Definition darktable.h:788
int kernel_blendop_mask_rgb_jzczhz
Definition blend.h:247
int kernel_blendop_display_channel
Definition blend.h:254
int kernel_blendop_rgb_jzczhz
Definition blend.h:251
int kernel_blendop_mask_rgb_hsl
Definition blend.h:246
int kernel_blendop_mask_tone_curve
Definition blend.h:252
dt_iop_buffer_dsc_t dsc_in
dt_dev_pixelpipe_type_t type
gboolean store_all_raster_masks
GArray * raster_mask_hashes
float blendif_parameters[4 *DEVELOP_BLENDIF_SIZE]
Definition blend.h:233
float blendif_boost_factors[DEVELOP_BLENDIF_SIZE]
Definition blend.h:234
int32_t gui_attached
Definition develop.h:162
GList * iop
Definition develop.h:285
struct dt_iop_module_t * gui_module
Definition develop.h:165
struct dt_dev_pixelpipe_t * pipe
Definition develop.h:247
unsigned int channels
Definition format.h:54
struct dt_develop_t * dev
Definition imageop.h:333
GModule *dt_dev_operation_t op
Definition imageop.h:286
struct dt_iop_module_t::@29 raster_mask
struct dt_iop_module_t::@29::@30 source
int request_mask_display
Definition imageop.h:298
struct dt_iop_module_t::@29::@31 sink
dt_colormatrix_t matrix_out_transposed
Definition iop_profile.h:66
Region of interest passed through the pixelpipe.
Definition imageop.h:72
double scale
Definition imageop.h:74
dt_masks_type_t type
Definition masks.h:380
GList * points
Definition masks.h:379
struct dt_blendop_cl_global_t * blendop
Definition opencl.h:278
uint64_t dt_supervisor_node_key(const int pipe_type, const char *op_name, const int multi_priority)
Definition supervisor.c:161
void dt_supervisor_cacheline_create(const uint64_t hash, const uint64_t node_hash, const uint64_t param_hash, const uint64_t input_hash, const char *op_name, const int multi_priority, const int iop_order, const int pipe_type, const int32_t imgid, const int roi_w, const int roi_h, const int devid, const size_t size, const char *name)
Definition supervisor.c:891
static gboolean dt_supervisor_active(void)
Definition supervisor.h:94
#define MAX(a, b)
Definition thinplate.c:29
static const int mask_id
Definition useless.c:210