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/tiling.h"
55#include <inttypes.h>
56#include <math.h>
57#include <string.h>
58
67
68static const char *dt_pipe_type_to_str(dt_dev_pixelpipe_type_t pipe_type)
69{
70 switch(pipe_type)
71 {
73 return "PREVIEW";
75 return "FULL";
77 return "THUMBNAIL";
79 return "EXPORT";
80 default:
81 return "UNKNOWN";
82 }
83}
84
89 0.0f,
90 100.0f,
92 0,
93 0,
94 0.0f,
96 0.0f,
97 0.0f,
98 0.0f,
99 0.0f, // detail mask threshold
100 { 0, 0, 0 },
101 { 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,
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, 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 },
106 { 0 }, 0, 0, FALSE };
107
109 gboolean is_scene_referred)
110{
111 if(module->flags() & IOP_FLAGS_SUPPORTS_BLENDING)
112 {
113 switch(module->blend_colorspace(module, NULL, NULL))
114 {
115 case IOP_CS_RAW:
117 case IOP_CS_LAB:
118 case IOP_CS_LCH:
120 case IOP_CS_RGB:
122 return is_scene_referred ? DEVELOP_BLEND_CS_RGB_SCENE : DEVELOP_BLEND_CS_RGB_DISPLAY;
123 case IOP_CS_HSL:
125 case IOP_CS_JZCZHZ:
127 default:
129 }
130 }
131 else
133}
134
139
142{
144 {
145 // update the default boost parameters for Jz and Cz so that the sRGB white is represented by a value
146 // "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
147 // as 1.8. In order to allow enough sensitivity in the low values, the boost factor should be set to
148 // log2(0.001) = -6.64385619. To keep the minimum boost factor at zero an offset of that value is added in
149 // the GUI. To display the initial boost factor at zero, the default value will be set to that value also.
150 blend_params->blendif_boost_factors[DEVELOP_BLENDIF_Jz_in] = -6.64385619f;
151 blend_params->blendif_boost_factors[DEVELOP_BLENDIF_Cz_in] = -6.64385619f;
152 blend_params->blendif_boost_factors[DEVELOP_BLENDIF_Jz_out] = -6.64385619f;
153 blend_params->blendif_boost_factors[DEVELOP_BLENDIF_Cz_out] = -6.64385619f;
154 }
155}
156
159{
160 memcpy(blend_params, &_default_blendop_params, sizeof(dt_develop_blend_params_t));
161 blend_params->blend_cst = cst;
162 _blend_init_blendif_boost_parameters(blend_params, cst);
163}
164
178
181{
182 const dt_develop_blend_params_t *const bp = (const dt_develop_blend_params_t *)piece->blendop_data;
183 if(IS_NULL_PTR(bp)) return cst;
184 switch(bp->blend_cst)
185 {
187 return IOP_CS_RAW;
189 return IOP_CS_LAB;
192 return IOP_CS_RGB;
193 default:
194 return cst;
195 }
196}
197
198void dt_develop_blendif_process_parameters(float *const restrict parameters,
199 const dt_develop_blend_params_t *const params)
200{
201 const int32_t blend_csp = params->blend_cst;
202 const uint32_t blendif = params->blendif;
203 const float *blendif_parameters = params->blendif_parameters;
204 const float *boost_factors = params->blendif_boost_factors;
205 for(size_t i = 0, j = 0; i < DEVELOP_BLENDIF_SIZE; i++, j += DEVELOP_BLENDIF_PARAMETER_ITEMS)
206 {
207 if(blendif & (1 << i))
208 {
209 float offset = 0.0f;
212 {
213 offset = 0.5f;
214 }
215 parameters[j + 0] = (blendif_parameters[i * 4 + 0] - offset) * exp2f(boost_factors[i]);
216 parameters[j + 1] = (blendif_parameters[i * 4 + 1] - offset) * exp2f(boost_factors[i]);
217 parameters[j + 2] = (blendif_parameters[i * 4 + 2] - offset) * exp2f(boost_factors[i]);
218 parameters[j + 3] = (blendif_parameters[i * 4 + 3] - offset) * exp2f(boost_factors[i]);
219 // pre-compute increasing slope and decreasing slope
220 parameters[j + 4] = 1.0f / fmaxf(0.001f, parameters[j + 1] - parameters[j + 0]);
221 parameters[j + 5] = 1.0f / fmaxf(0.001f, parameters[j + 3] - parameters[j + 2]);
222 // handle the case when one end is open to avoid clipping input/output values
223 if(blendif_parameters[i * 4 + 0] <= 0.0f && blendif_parameters[i * 4 + 1] <= 0.0f)
224 {
225 parameters[j + 0] = -INFINITY;
226 parameters[j + 1] = -INFINITY;
227 }
228 if(blendif_parameters[i * 4 + 2] >= 1.0f && blendif_parameters[i * 4 + 3] >= 1.0f)
229 {
230 parameters[j + 2] = INFINITY;
231 parameters[j + 3] = INFINITY;
232 }
233 }
234 else
235 {
236 parameters[j + 0] = -INFINITY;
237 parameters[j + 1] = -INFINITY;
238 parameters[j + 2] = INFINITY;
239 parameters[j + 3] = INFINITY;
240 parameters[j + 4] = 0.0f;
241 parameters[j + 5] = 0.0f;
242 }
243 }
244}
245
247 const dt_develop_blend_params_t *params,
248 gboolean *top_enabled,
249 gboolean *raster_used,
250 gboolean *drawn_used,
251 gboolean *parametric_used)
252{
253 if(!IS_NULL_PTR(top_enabled)) *top_enabled = FALSE;
254 if(!IS_NULL_PTR(raster_used)) *raster_used = FALSE;
255 if(!IS_NULL_PTR(drawn_used)) *drawn_used = FALSE;
256 if(!IS_NULL_PTR(parametric_used)) *parametric_used = FALSE;
257 if(IS_NULL_PTR(params)) return;
258
259 const uint32_t mask_mode = params->mask_mode;
260 const gboolean top = (mask_mode & DEVELOP_MASK_ENABLED) != 0;
261 const gboolean raster_mode = (mask_mode & DEVELOP_MASK_RASTER) != 0;
262 const gboolean drawn_mode = (mask_mode & DEVELOP_MASK_SHAPE) != 0;
263 const gboolean parametric_mode = (mask_mode & DEVELOP_MASK_PARAMETRIC) != 0;
264
265 gboolean raster = raster_mode
266 && (params->raster_mask_id > 0
267 || params->raster_mask_source[0] != '\0'
268 || (!IS_NULL_PTR(module) && !IS_NULL_PTR(module->raster_mask.sink.source)));
269
270 gboolean drawn = FALSE;
271 if(drawn_mode && !IS_NULL_PTR(module) && !IS_NULL_PTR(module->dev))
272 {
273 dt_masks_form_t *grp = dt_masks_get_from_id(module->dev, params->mask_id);
274 drawn = !IS_NULL_PTR(grp) && (grp->type & DT_MASKS_GROUP) && g_list_length(grp->points) > 0;
275 }
276
277 gboolean parametric = FALSE;
278 if(parametric_mode)
279 {
280 const float threshold_epsilon = 1e-6f;
281 const uint32_t channel_mask = params->blend_cst == DEVELOP_BLEND_CS_LAB
284 uint32_t active_channels = 0;
285 for(uint32_t ch = 0; ch < DEVELOP_BLENDIF_SIZE; ch++)
286 {
287 const uint32_t bit = 1u << ch;
288 if(!(channel_mask & bit) || !(params->blendif & bit)) continue;
289 const float *channel = &params->blendif_parameters[ch * 4];
290 if(fabsf(channel[0]) > threshold_epsilon
291 || fabsf(channel[1]) > threshold_epsilon
292 || fabsf(channel[2] - 1.0f) > threshold_epsilon
293 || fabsf(channel[3] - 1.0f) > threshold_epsilon)
294 active_channels |= bit;
295 }
296 parametric = active_channels != 0;
297 }
298
299 if(!IS_NULL_PTR(top_enabled)) *top_enabled = top;
300 if(!IS_NULL_PTR(raster_used)) *raster_used = raster;
301 if(!IS_NULL_PTR(drawn_used)) *drawn_used = drawn;
302 if(!IS_NULL_PTR(parametric_used)) *parametric_used = parametric;
303}
304
305// See function definition in blend.h for important information
307 const struct dt_dev_pixelpipe_iop_t *piece,
308 dt_iop_order_iccprofile_info_t *blending_profile,
310{
311 // Bradford adaptation matrix from http://www.brucelindbloom.com/index.html?Eqn_ChromAdapt.html
312 const dt_colormatrix_t M = {
313 { 0.9555766f, -0.0230393f, 0.0631636f, 0.0f },
314 { -0.0282895f, 1.0099416f, 0.0210077f, 0.0f },
315 { 0.0122982f, -0.0204830f, 1.3299098f, 0.0f },
316 };
317
318 const dt_iop_order_iccprofile_info_t *const profile = (cst == DEVELOP_BLEND_CS_RGB_SCENE)
319 ? dt_ioppr_get_pipe_current_profile_info(piece->module, pipe)
320 : dt_ioppr_get_iop_work_profile_info(piece->module, piece->module->dev->iop);
321 if(IS_NULL_PTR(profile)) return 0;
322
323 memcpy(blending_profile, profile, sizeof(dt_iop_order_iccprofile_info_t));
324 for(size_t y = 0; y < 3; y++)
325 {
326 for(size_t x = 0; x < 3; x++)
327 {
328 float sum = 0.0f;
329 for(size_t i = 0; i < 3; i++)
330 sum += M[y][i] * profile->matrix_in[i][x];
331 blending_profile->matrix_out[y][x] = sum;
332 blending_profile->matrix_out_transposed[x][y] = sum;
333 }
334 }
335
336 return 1;
337}
338
339static inline float _detail_mask_threshold(const float level, const gboolean detail)
340{
341 // this does some range calculation for smoother ui experience
342 return 0.005f * (detail ? powf(level, 2.0f) : 1.0f - powf(fabs(level), 0.5f ));
343}
344
345static void _refine_with_detail_mask(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe,
346 const struct dt_dev_pixelpipe_iop_t *piece, float *mask,
347 const float level)
348{
349 const dt_iop_roi_t *const roi_out = &piece->roi_out;
350 if(level == 0.0f) return;
351 const gboolean info = ((darktable.unmuted & DT_DEBUG_MASKS) && (pipe->type == DT_DEV_PIXELPIPE_FULL));
352
353 const gboolean detail = (level > 0.0f);
354 const float threshold = _detail_mask_threshold(level, detail);
355
356 float *tmp = NULL;
357 float *lum = NULL;
358 float *warp_mask = NULL;
359 float *rawdetail_mask = NULL;
360
361 const dt_dev_pixelpipe_t *p = pipe;
362 rawdetail_mask = dt_dev_retrieve_rawdetail_mask(pipe, self);
363 if(IS_NULL_PTR(rawdetail_mask)) return;
364
365 const int iwidth = p->rawdetail_mask_roi.width;
366 const int iheight = p->rawdetail_mask_roi.height;
367 const int owidth = roi_out->width;
368 const int oheight = roi_out->height;
369 if(info) fprintf(stderr, "[_refine_with_detail_mask] in module %s %ix%i --> %ix%i\n", self->op, iwidth, iheight, owidth, oheight);
370
371 const int bufsize = MAX(iwidth * iheight, owidth * oheight);
372
373 tmp = dt_pixelpipe_cache_alloc_align_float(bufsize, pipe);
374 lum = dt_pixelpipe_cache_alloc_align_float(bufsize, pipe);
375 if((IS_NULL_PTR(tmp)) || (IS_NULL_PTR(lum))) goto error;
376
377 dt_masks_calc_detail_mask(rawdetail_mask, lum, tmp, iwidth, iheight, threshold, detail);
379 tmp = NULL;
380
381 // here we have the slightly blurred full detail mask available
382 warp_mask = dt_dev_distort_detail_mask(p, lum, self);
383 // dt_dev_distort_detail_mask() may return `lum` unchanged when no geometric distortion is needed.
384 const gboolean warp_mask_aliases_lum = (warp_mask == lum);
385 if(!warp_mask_aliases_lum)
386 {
388 lum = NULL;
389 }
390
391 if(IS_NULL_PTR(warp_mask)) goto error;
392
393 const int msize = owidth * oheight;
394 __OMP_PARALLEL_FOR_SIMD__(aligned(mask, warp_mask : 64))
395 for(int idx =0; idx < msize; idx++)
396 {
397 mask[idx] = mask[idx] * warp_mask[idx];
398 }
400 if(warp_mask_aliases_lum) lum = NULL;
401
402 return;
403
404 error:
405 dt_control_log(_("detail mask blending error"));
409}
410
412 const dt_dev_pixelpipe_iop_t *const piece,
413 _develop_mask_post_processing operations[3])
414{
415 const gboolean mask_feather = params->feathering_radius > 0.1f && piece->dsc_in.channels >= 3;
416 const gboolean mask_blur = params->blur_radius > 0.1f;
417 const gboolean mask_tone_curve = fabsf(params->contrast) >= 0.01f || fabsf(params->brightness) >= 0.01f;
418 const gboolean mask_feather_before = params->feathering_guide == DEVELOP_MASK_GUIDE_IN_BEFORE_BLUR
419 || params->feathering_guide == DEVELOP_MASK_GUIDE_OUT_BEFORE_BLUR;
420 const gboolean mask_feather_out = params->feathering_guide == DEVELOP_MASK_GUIDE_OUT_BEFORE_BLUR
421 || params->feathering_guide == DEVELOP_MASK_GUIDE_OUT_AFTER_BLUR;
422 const float opacity = fminf(fmaxf(params->opacity / 100.0f, 0.0f), 1.0f);
423
424 memset(operations, 0, sizeof(_develop_mask_post_processing) * 3);
425 size_t index = 0;
426
427 if(mask_feather)
428 {
429 if(mask_blur && mask_feather_before)
430 {
431 operations[index++] = mask_feather_out ? DEVELOP_MASK_POST_FEATHER_OUT : DEVELOP_MASK_POST_FEATHER_IN;
432 operations[index++] = DEVELOP_MASK_POST_BLUR;
433 }
434 else
435 {
436 if(mask_blur)
437 operations[index++] = DEVELOP_MASK_POST_BLUR;
438 operations[index++] = mask_feather_out ? DEVELOP_MASK_POST_FEATHER_OUT : DEVELOP_MASK_POST_FEATHER_IN;
439 }
440 }
441 else if(mask_blur)
442 {
443 operations[index++] = DEVELOP_MASK_POST_BLUR;
444 }
445
446 if(mask_tone_curve && opacity > 1e-4f)
447 {
448 operations[index++] = DEVELOP_MASK_POST_TONE_CURVE;
449 }
450
451 return index;
452}
453
454
455static inline float *_develop_blend_process_copy_region(const float *const restrict input, const size_t iwidth,
456 const size_t xoffs, const size_t yoffs,
457 const size_t owidth, const size_t oheight)
458{
459 const size_t ioffset = yoffs * iwidth + xoffs;
460 float *const restrict output =
462 if(IS_NULL_PTR(output))
463 {
464 return NULL;
465 }
467 for(size_t y = 0; y < oheight; y++)
468 {
469 const size_t iindex = y * iwidth + ioffset;
470 const size_t oindex = y * owidth;
471 memcpy(output + oindex, input + iindex, sizeof(float) * owidth);
472 }
473
474 return output;
475}
476
477static inline void _develop_blend_process_free_region(float *const restrict input)
478{
480}
481
483 const dt_iop_module_t *const self)
484{
485 if(IS_NULL_PTR(params) || IS_NULL_PTR(self)) return NULL;
486
487 const dt_iop_module_t *source = self->raster_mask.sink.source;
488 if(source && !strcmp(source->op, params->raster_mask_source)
489 && source->multi_priority == params->raster_mask_instance)
490 return source;
491
492 if(IS_NULL_PTR(self->dev) || params->raster_mask_source[0] == '\0') return NULL;
493
494 for(GList *iter = g_list_first(self->dev->iop); iter; iter = g_list_next(iter))
495 {
496 const dt_iop_module_t *candidate = (const dt_iop_module_t *)iter->data;
497 if(!strcmp(candidate->op, params->raster_mask_source)
498 && candidate->multi_priority == params->raster_mask_instance)
499 return candidate;
500 }
501
502 return NULL;
503}
504
506 dt_iop_module_t *self,
507 dt_dev_pixelpipe_t *pipe,
508 const dt_dev_pixelpipe_iop_t *piece,
509 float *const restrict mask,
510 const size_t owidth,
511 const size_t oheight,
512 int *const raster_error)
513{
514 int local_raster_error = 0;
515 const dt_iop_module_t *raster_source = _develop_blend_get_raster_source_module(params, self);
516 float *raster_mask = raster_source
517 ? dt_dev_get_raster_mask(pipe, raster_source, params->raster_mask_id,
518 self, &local_raster_error)
519 : NULL;
520
521 if(!IS_NULL_PTR(raster_mask))
522 {
523 if(params->raster_mask_invert)
524 {
525 __OMP_FOR_SIMD__(aligned(mask, raster_mask:64) )
526 for(size_t i = 0; i < owidth * oheight; i++)
527 mask[i] = 1.0f - raster_mask[i];
528 }
529 else
530 {
531 dt_iop_image_scaled_copy(mask, raster_mask, 1.0f, owidth, oheight, 1);
532 }
533
535 }
536 else
537 {
538 const float value = params->raster_mask_invert ? 0.0f : 1.0f;
539 dt_iop_image_fill(mask, value, owidth, oheight, 1);
540 }
541
542 if(!IS_NULL_PTR(raster_error)) *raster_error = local_raster_error;
543}
544
546 dt_iop_module_t *self,
547 dt_dev_pixelpipe_t *pipe,
548 const dt_dev_pixelpipe_iop_t *piece,
549 const struct dt_iop_roi_t *const roi_out,
550 float *const restrict mask,
551 const size_t owidth,
552 const size_t oheight)
553{
554 dt_masks_form_t *form = dt_masks_get_from_id(self->dev, params->mask_id);
555
556 if(form && (!(self->flags() & IOP_FLAGS_NO_MASKS)) && (params->mask_mode & DEVELOP_MASK_SHAPE))
557 {
558 if(dt_masks_group_render_roi(self, pipe, piece, form, roi_out, mask) != 0) return 1;
559
560 if(params->mask_combine & DEVELOP_COMBINE_MASKS_POS)
561 dt_iop_image_invert(mask, 1.0f, owidth, oheight, 1);
562 }
563 else if((!(self->flags() & IOP_FLAGS_NO_MASKS)) && (params->mask_mode & DEVELOP_MASK_SHAPE))
564 {
565 const float fill = (params->mask_combine & DEVELOP_COMBINE_MASKS_POS) ? 0.0f : 1.0f;
566 dt_iop_image_fill(mask, fill, owidth, oheight, 1);
567 }
568 else
569 {
570 const float fill = (params->mask_combine & DEVELOP_COMBINE_INCL) ? 0.0f : 1.0f;
571 dt_iop_image_fill(mask, fill, owidth, oheight, 1);
572 }
573
574 return 0;
575}
576
577static void _develop_blend_combine_masks(float *const restrict mask,
578 const float *const restrict other_mask,
579 const size_t buffsize)
580{
581 __OMP_FOR_SIMD__(aligned(mask, other_mask:64) )
582 for(size_t i = 0; i < buffsize; i++)
583 mask[i] *= other_mask[i];
584}
585
586
587static int _develop_blend_process_feather(const float *const guide, float *const mask, const size_t width,
588 const size_t height, const int ch, const float guide_weight,
589 const float feathering_radius, const float scale)
590{
591 const float sqrt_eps = 1.f;
592 int w = (int)(2 * feathering_radius * scale + 0.5f);
593 if(w < 1) w = 1;
594
595 float *const restrict mask_bak =
597 if(IS_NULL_PTR(mask_bak)) return 1;
598
599 memcpy(mask_bak, mask, sizeof(float) * width * height);
600 if(guided_filter(guide, mask_bak, mask, width, height, ch, w, sqrt_eps, guide_weight, 0.f, 1.f) != 0)
601 {
603 return 1;
604 }
606 return 0;
607}
608
609
610static void _develop_blend_process_mask_tone_curve(float *const restrict mask, const size_t buffsize,
611 const float contrast, const float brightness,
612 const float opacity)
613{
614 const float mask_epsilon = 16 * FLT_EPSILON; // empirical mask threshold for fully transparent masks
615 const float e = expf(3.f * contrast);
616 __OMP_PARALLEL_FOR_SIMD__(aligned(mask:64))
617 for(size_t k = 0; k < buffsize; k++)
618 {
619 float x = mask[k] / opacity;
620 x = 2.f * x - 1.f;
621 if (1.f - brightness <= 0.f)
622 x = mask[k] <= mask_epsilon ? -1.f : 1.f;
623 else if (1.f + brightness <= 0.f)
624 x = mask[k] >= 1.f - mask_epsilon ? 1.f : -1.f;
625 else if (brightness > 0.f)
626 {
627 x = (x + brightness) / (1.f - brightness);
628 x = fminf(x, 1.f);
629 }
630 else
631 {
632 x = (x + brightness) / (1.f + brightness);
633 x = fmaxf(x, -1.f);
634 }
635 mask[k] = clamp_range_f(
636 ((x * e / (1.f + (e - 1.f) * fabsf(x))) / 2.f + 0.5f) * opacity, 0.f, 1.f);
637 }
638}
639
640
642 const struct dt_dev_pixelpipe_iop_t *piece, const void *const ivoid,
643 void *const ovoid)
644{
645 const dt_iop_roi_t *const roi_in = &piece->roi_in;
646 const dt_iop_roi_t *const roi_out = &piece->roi_out;
647 if(pipe->bypass_blendif && self->dev->gui_attached && (self == self->dev->gui_module)) return 0;
648
649 const dt_develop_blend_params_t *const d = (const dt_develop_blend_params_t *const)piece->blendop_data;
650 if(IS_NULL_PTR(d)) return 0;
651
652 gboolean top_enabled = FALSE;
653 gboolean raster_used = FALSE;
654 gboolean drawn_used = FALSE;
655 gboolean parametric_used = FALSE;
656 dt_develop_blend_get_mask_usage(self, d, &top_enabled, &raster_used, &drawn_used, &parametric_used);
657 if(!top_enabled) return 0;
658 // A mask preview request must also be honored when every sub-mask is neutral.
659 // In that case no raster/drawn/parametric mask is "used", but the effective
660 // blend mask is still the uniform opacity mask written into alpha below.
661 const gboolean preview_mask_mode = top_enabled;
662
663 const size_t ch = piece->dsc_in.channels; // the number of channels in the buffer
664 const int xoffs = roi_out->x - roi_in->x;
665 const int yoffs = roi_out->y - roi_in->y;
666 const int iwidth = roi_in->width;
667 const int iheight = roi_in->height;
668 const int owidth = roi_out->width;
669 const int oheight = roi_out->height;
670 const size_t buffsize = (size_t)owidth * oheight;
671 const float iscale = roi_in->scale;
672 const float oscale = roi_out->scale;
673 const gboolean rois_equal = iwidth == owidth || iheight == oheight || xoffs == 0 || yoffs == 0;
674
675 // In most cases of blending-enabled modules input and output of the module have
676 // the exact same dimensions. Only in very special cases we allow a module's input
677 // to exceed its output. This is namely the case for the spot removal module where
678 // the source of a patch might lie outside the roi of the output image. Therefore:
679 // We can only handle blending if roi_out and roi_in have the same scale and
680 // if roi_out fits into the area given by roi_in. xoffs and yoffs describe the relative
681 // offset of the input image to the output image.
682 if(oscale != iscale || xoffs < 0 || yoffs < 0
683 || ((xoffs > 0 || yoffs > 0) && (owidth + xoffs > iwidth || oheight + yoffs > iheight)))
684 {
685 dt_control_log(_("skipped blending in module '%s': roi's do not match"), self->op);
686 return 0;
687 }
688
689 // does user want us to display a specific channel?
690 const dt_dev_pixelpipe_display_mask_t request_mask_display =
691 (self->dev->gui_attached && (self == self->dev->gui_module) && (pipe == self->dev->pipe)
692 && preview_mask_mode)
695
696 // get channel max values depending on colorspace
697 const dt_develop_blend_colorspace_t blend_csp = d->blend_cst;
699
700 // obtaining the list of mask operations to perform
701 _develop_mask_post_processing post_operations[3];
702 const size_t post_operations_size = _develop_mask_get_post_operations(d, piece, post_operations);
703
704 // get the clipped opacity value 0 - 1
705 const float opacity = fminf(fmaxf(d->opacity / 100.0f, 0.0f), 1.0f);
706
707 // allocate space for blend mask
708 float *const restrict _mask = dt_pixelpipe_cache_alloc_align_float(buffsize, pipe);
709 if(IS_NULL_PTR(_mask))
710 {
711 dt_control_log(_("could not allocate buffer for blending"));
712 return 1;
713 }
714 int raster_error = 0;
715 float *const restrict mask = _mask;
716 const gboolean use_masks = raster_used || drawn_used || parametric_used;
717 const gboolean raster_only = raster_used && !drawn_used && !parametric_used;
718
719 if(!use_masks)
720 {
721 // blend uniformly (no drawn or parametric mask)
722 dt_iop_image_fill(mask,opacity,owidth,oheight,1); //mask[k] = opacity;
723 }
724 else if(raster_only)
725 {
726 /* use a raster mask from another module earlier in the pipe */
727 _develop_blend_init_raster_mask(d, self, pipe, piece, mask, owidth, oheight, &raster_error);
728 dt_iop_image_mul_const(mask, opacity, owidth, oheight, 1);
729 }
730 else
731 {
732 if(!raster_used && !drawn_used)
733 {
734 // Parametric-only blending has no raster/drawn form mask to seed `mask`.
735 // The combination code below loops on parametric channels and composes them
736 // with that form mask, so initialize it as the neutral value of the chosen
737 // mask-combine operator.
738 const float fill = (d->mask_combine & DEVELOP_COMBINE_INCL) ? 0.0f : 1.0f;
739 dt_iop_image_fill(mask, fill, owidth, oheight, 1);
740 }
741 else if(raster_used)
742 {
743 _develop_blend_init_raster_mask(d, self, pipe, piece, mask, owidth, oheight, &raster_error);
744
745 if(drawn_used)
746 {
747 float *const restrict drawn_mask = dt_pixelpipe_cache_alloc_align_float(buffsize, pipe);
748 if(IS_NULL_PTR(drawn_mask))
749 {
750 dt_control_log(_("could not allocate buffer for blending"));
752 return 1;
753 }
754
755 if(_develop_blend_init_drawn_mask(d, self, pipe, piece, roi_out, drawn_mask, owidth, oheight) != 0)
756 {
759 return 1;
760 }
761
762 _develop_blend_combine_masks(mask, drawn_mask, buffsize);
764 }
765 }
766 else if(drawn_used
767 && _develop_blend_init_drawn_mask(d, self, pipe, piece, roi_out, mask, owidth, oheight) != 0)
768 {
770 return 1;
771 }
772
773 _refine_with_detail_mask(self, pipe, piece, mask, d->details);
774
775 // get parametric mask (if any) and apply global opacity
776 switch(blend_csp)
777 {
779 dt_develop_blendif_lab_make_mask(piece, (const float *const restrict)ivoid,
780 (const float *const restrict)ovoid, mask);
781 break;
783 dt_develop_blendif_rgb_hsl_make_mask(pipe, piece, (const float *const restrict)ivoid,
784 (const float *const restrict)ovoid, mask);
785 break;
787 dt_develop_blendif_rgb_jzczhz_make_mask(pipe, piece, (const float *const restrict)ivoid,
788 (const float *const restrict)ovoid, mask);
789 break;
791 dt_develop_blendif_raw_make_mask(piece, (const float *const restrict)ivoid,
792 (const float *const restrict)ovoid, mask);
793 break;
794 default:
795 break;
796 }
797
798 // post processing the mask
799 for(size_t index = 0; index < post_operations_size; ++index)
800 {
801 _develop_mask_post_processing operation = post_operations[index];
802 if(operation == DEVELOP_MASK_POST_FEATHER_IN)
803 {
804 const float guide_weight = dt_iop_colorspace_is_rgb(cst) ? 100.0f : 1.0f;
805 float *restrict guide = (float *restrict)ivoid;
806 if(!rois_equal)
807 guide = _develop_blend_process_copy_region(guide, ch * iwidth, ch * xoffs, ch * yoffs,
808 ch * owidth, ch * oheight);
809 if(!guide)
810 {
812 return 1;
813 }
814 if(_develop_blend_process_feather(guide, mask, owidth, oheight, ch, guide_weight,
815 d->feathering_radius, roi_out->scale) != 0)
816 {
817 if(!rois_equal)
820 return 1;
821 }
822 if(!rois_equal)
824 }
825 else if(operation == DEVELOP_MASK_POST_FEATHER_OUT)
826 {
827 const float guide_weight = dt_iop_colorspace_is_rgb(cst) ? 100.0f : 1.0f;
828 if(_develop_blend_process_feather((const float *const restrict)ovoid, mask, owidth, oheight, ch,
829 guide_weight, d->feathering_radius, roi_out->scale) != 0)
830 {
832 return 1;
833 }
834 }
835 else if(operation == DEVELOP_MASK_POST_BLUR)
836 {
837 const float sigma = d->blur_radius * roi_out->scale;
838 const float mmax[] = { 1.0f };
839 const float mmin[] = { 0.0f };
840
841 dt_gaussian_t *g = dt_gaussian_init(owidth, oheight, 1, mmax, mmin, sigma, 0);
842 if(g)
843 {
844 dt_gaussian_blur(g, mask, mask);
846 }
847 }
848 else if(operation == DEVELOP_MASK_POST_TONE_CURVE)
849 {
850 _develop_blend_process_mask_tone_curve(mask, buffsize, d->contrast, d->brightness, opacity);
851 }
852 }
853 }
854
855 // now apply blending with per-pixel opacity value as defined in mask
856 // select the blend operator
857 switch(blend_csp)
858 {
860 dt_develop_blendif_lab_blend(pipe, piece, (const float *const restrict)ivoid, (float *const restrict)ovoid,
861 mask, request_mask_display);
862 break;
864 dt_develop_blendif_rgb_hsl_blend(pipe, piece, (const float *const restrict)ivoid, (float *const restrict)ovoid,
865 mask, request_mask_display);
866 break;
868 dt_develop_blendif_rgb_jzczhz_blend(pipe, piece, (const float *const restrict)ivoid, (float *const restrict)ovoid,
869 mask, request_mask_display);
870 break;
872 dt_develop_blendif_raw_blend(pipe, piece, (const float *const restrict)ivoid, (float *const restrict)ovoid,
873 mask, request_mask_display);
874 break;
875 default:
876 break;
877 }
878
879 // register if _this_ module should expose mask or display channel
881 {
882 pipe->mask_display = request_mask_display;
883 }
884
885 // check if we should store the mask for export or use in subsequent modules
887 {
888 const uint64_t mask_hash = dt_dev_pixelpipe_raster_mask_hash(piece, 0);
889 dt_pixel_cache_entry_t *mask_entry = NULL;
890 void *cache_data = NULL;
891 const int created = dt_dev_pixelpipe_cache_get(
892 darktable.pixelpipe_cache, mask_hash, sizeof(float) * buffsize,
893 "raster mask", pipe->type, TRUE, &cache_data, &mask_entry);
894
895 if(IS_NULL_PTR(cache_data) || IS_NULL_PTR(mask_entry))
896 {
897 if(created && !IS_NULL_PTR(mask_entry))
899 if(!IS_NULL_PTR(mask_entry))
900 {
902 if(created)
904 }
906 return 1;
907 }
908
909 // Cache entries are immutable for a given provider state. Only the thread
910 // which created this dedicated key writes the mask; exact hits reuse it.
911 if(created)
912 {
913 memcpy(cache_data, _mask, sizeof(float) * buffsize);
915 }
916 // Transfer cache_get()'s reference to the pipe. It keeps this side-band
917 // output alive until the next graph state is prepared or the pipe closes.
918 g_array_append_val(pipe->raster_mask_hashes, mask_hash);
920
922 "[raster masks] %s mask id 0 for module %s (%s) for pipe %s"
923 " with cache hash %" PRIu64 "\n",
924 created ? "published" : "reused cached",
925 piece->module->op, piece->module->multi_name,
926 dt_pipe_type_to_str(pipe->type), mask_hash);
927 }
928 else
929 {
931 "[raster masks] discarding unpublished mask id 0 for module %s (%s) for pipe %s\n",
932 piece->module->op, piece->module->multi_name,
935 }
936 // raster error is the only one we catch
937 return raster_error;
938}
939
940#ifdef HAVE_OPENCL
941static void _refine_with_detail_mask_cl(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe,
942 const struct dt_dev_pixelpipe_iop_t *piece, float *mask,
943 const float level, const int devid)
944{
945 const dt_iop_roi_t *const roi_out = &piece->roi_out;
946 if(level == 0.0f) return;
947 const gboolean info = (darktable.unmuted & DT_DEBUG_MASKS);
948
949 const int detail = (level > 0.0f);
950 const float threshold = _detail_mask_threshold(level, detail);
951 float *lum = NULL;
952 float *rawdetail_mask = NULL;
953 cl_mem tmp = NULL;
954 cl_mem blur = NULL;
955 cl_mem out = NULL;
956
957 const dt_dev_pixelpipe_t *p = pipe;
958 rawdetail_mask = dt_dev_retrieve_rawdetail_mask(pipe, self);
959 if(IS_NULL_PTR(rawdetail_mask)) return;
960
961 const int iwidth = p->rawdetail_mask_roi.width;
962 const int iheight = p->rawdetail_mask_roi.height;
963 const int owidth = roi_out->width;
964 const int oheight = roi_out->height;
965 if(info) fprintf(stderr, "[_refine_with_detail_mask_cl] in module %s %ix%i --> %ix%i\n", self->op, iwidth, iheight, owidth, oheight);
966
967 lum = dt_pixelpipe_cache_alloc_align_float((size_t)iwidth * iheight, pipe);
968 if(IS_NULL_PTR(lum)) goto error;
969 tmp = dt_opencl_alloc_device(devid, iwidth, iheight, sizeof(float));
970 if(IS_NULL_PTR(tmp)) goto error;
971 out = dt_opencl_alloc_device_buffer(devid, sizeof(float) * iwidth * iheight);
972 if(IS_NULL_PTR(out)) goto error;
973 blur = dt_opencl_alloc_device_buffer(devid, sizeof(float) * iwidth * iheight);
974 if(IS_NULL_PTR(blur)) goto error;
975
976 {
977 const int err = dt_opencl_write_host_to_device(devid, rawdetail_mask, tmp, iwidth, iheight, sizeof(float));
978 if(err != CL_SUCCESS) goto error;
979 }
980
981 {
982 size_t sizes[3] = { ROUNDUPDWD(iwidth, devid), ROUNDUPDHT(iheight, devid), 1 };
984 dt_opencl_set_kernel_arg(devid, kernel, 0, sizeof(cl_mem), &out);
985 dt_opencl_set_kernel_arg(devid, kernel, 1, sizeof(cl_mem), &tmp);
986 dt_opencl_set_kernel_arg(devid, kernel, 2, sizeof(int), &iwidth);
987 dt_opencl_set_kernel_arg(devid, kernel, 3, sizeof(int), &iheight);
988 const int err = dt_opencl_enqueue_kernel_2d(devid, kernel, sizes);
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), &blur);
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 dt_opencl_set_kernel_arg(devid, kernel, 4, sizeof(float), &threshold);
1000 dt_opencl_set_kernel_arg(devid, kernel, 5, sizeof(int), &detail);
1001 const int err = dt_opencl_enqueue_kernel_2d(devid, kernel, sizes);
1002 if(err != CL_SUCCESS) goto error;
1003 }
1004
1005 {
1006 float blurmat[13];
1007 dt_masks_blur_9x9_coeff(blurmat, 2.0f);
1008 cl_mem dev_blurmat = NULL;
1009 dev_blurmat = dt_opencl_copy_host_to_device_constant(devid, sizeof(float) * 13, blurmat);
1010 if(!IS_NULL_PTR(dev_blurmat))
1011 {
1012 size_t sizes[3] = { ROUNDUPDWD(iwidth, devid), ROUNDUPDHT(iheight, devid), 1 };
1013 const int clkernel = darktable.opencl->blendop->kernel_mask_blur;
1014 dt_opencl_set_kernel_arg(devid, clkernel, 0, sizeof(cl_mem), &blur);
1015 dt_opencl_set_kernel_arg(devid, clkernel, 1, sizeof(cl_mem), &out);
1016 dt_opencl_set_kernel_arg(devid, clkernel, 2, sizeof(int), &iwidth);
1017 dt_opencl_set_kernel_arg(devid, clkernel, 3, sizeof(int), &iheight);
1018 dt_opencl_set_kernel_arg(devid, clkernel, 4, sizeof(cl_mem), (void *) &dev_blurmat);
1019 const int err = dt_opencl_enqueue_kernel_2d(devid, clkernel, sizes);
1020 dt_opencl_release_mem_object(dev_blurmat);
1021 if(err != CL_SUCCESS) goto error;
1022 }
1023 else
1024 {
1025 dt_opencl_release_mem_object(dev_blurmat);
1026 goto error;
1027 }
1028 }
1029
1030 {
1031 size_t sizes[3] = { ROUNDUPDWD(iwidth, devid), ROUNDUPDHT(iheight, devid), 1 };
1033 dt_opencl_set_kernel_arg(devid, kernel, 0, sizeof(cl_mem), &out);
1034 dt_opencl_set_kernel_arg(devid, kernel, 1, sizeof(cl_mem), &tmp);
1035 dt_opencl_set_kernel_arg(devid, kernel, 2, sizeof(int), &iwidth);
1036 dt_opencl_set_kernel_arg(devid, kernel, 3, sizeof(int), &iheight);
1037 const int err = dt_opencl_enqueue_kernel_2d(devid, kernel, sizes);
1038 if(err != CL_SUCCESS) goto error;
1039 }
1040
1041 {
1042 const int err = dt_opencl_read_host_from_device(devid, lum, tmp, iwidth, iheight, sizeof(float));
1043 if(err != CL_SUCCESS) goto error;
1044 }
1045
1049 tmp = blur = out = NULL;
1050
1051 // here we have the slightly blurred full detail available
1052 float *warp_mask = dt_dev_distort_detail_mask(p, lum, self);
1053 if(IS_NULL_PTR(warp_mask)) goto error;
1054 // dt_dev_distort_detail_mask() may return `lum` unchanged when no geometric distortion is needed.
1055 const gboolean warp_mask_aliases_lum = (warp_mask == lum);
1056 if(!warp_mask_aliases_lum)
1057 {
1059 lum = NULL;
1060 }
1061
1062 const int msize = owidth * oheight;
1063 __OMP_PARALLEL_FOR_SIMD__(aligned(mask, warp_mask : 64))
1064 for(int idx = 0; idx < msize; idx++)
1065 {
1066 mask[idx] = mask[idx] * warp_mask[idx];
1067 }
1069 if(warp_mask_aliases_lum) lum = NULL;
1070 return;
1071
1072 error:
1073 dt_control_log(_("detail mask CL blending problem"));
1078}
1079
1080static inline void _blend_process_cl_exchange(cl_mem *a, cl_mem *b)
1081{
1082 cl_mem tmp = *a;
1083 *a = *b;
1084 *b = tmp;
1085}
1086
1088 const struct dt_dev_pixelpipe_iop_t *piece, cl_mem dev_in, cl_mem dev_out)
1089{
1090 const dt_iop_roi_t *const roi_in = &piece->roi_in;
1091 const dt_iop_roi_t *const roi_out = &piece->roi_out;
1092 if(pipe->bypass_blendif && self->dev->gui_attached && (self == self->dev->gui_module)) return 0;
1093
1095 if(IS_NULL_PTR(d)) return 0;
1096
1097 gboolean top_enabled = FALSE;
1098 gboolean raster_used = FALSE;
1099 gboolean drawn_used = FALSE;
1100 gboolean parametric_used = FALSE;
1101 dt_develop_blend_get_mask_usage(self, d, &top_enabled, &raster_used, &drawn_used, &parametric_used);
1102 if(!top_enabled) return 0;
1103 const unsigned int mask_mode = d->mask_mode;
1104 // A mask preview request must also be honored when every sub-mask is neutral.
1105 // In that case no raster/drawn/parametric mask is "used", but the effective
1106 // blend mask is still the uniform opacity mask written into alpha below.
1107 const gboolean preview_mask_mode = top_enabled;
1108
1109 const int ch = piece->dsc_in.channels; // the number of channels in the buffer
1110 const int xoffs = roi_out->x - roi_in->x;
1111 const int yoffs = roi_out->y - roi_in->y;
1112 const int iwidth = roi_in->width;
1113 const int iheight = roi_in->height;
1114 const int owidth = roi_out->width;
1115 const int oheight = roi_out->height;
1116 const size_t buffsize = (size_t)owidth * oheight;
1117 const float iscale = roi_in->scale;
1118 const float oscale = roi_out->scale;
1119 const gboolean rois_equal = iwidth == owidth || iheight == oheight || xoffs == 0 || yoffs == 0;
1120
1121 // In most cases of blending-enabled modules input and output of the module have
1122 // the exact same dimensions. Only in very special cases we allow a module's input
1123 // to exceed its output. This is namely the case for the spot removal module where
1124 // the source of a patch might lie outside the roi of the output image. Therefore:
1125 // We can only handle blending if roi_out and roi_in have the same scale and
1126 // if roi_out fits into the area given by roi_in. xoffs and yoffs describe the relative
1127 // offset of the input image to the output image. */
1128 if(oscale != iscale || xoffs < 0 || yoffs < 0
1129 || ((xoffs > 0 || yoffs > 0) && (owidth + xoffs > iwidth || oheight + yoffs > iheight)))
1130 {
1131 dt_control_log(_("skipped blending in module '%s': roi's do not match"), self->op);
1132 return 0;
1133 }
1134
1135 // only non-zero if mask_display was set by an _earlier_ module
1136 const dt_dev_pixelpipe_display_mask_t mask_display = pipe->mask_display;
1137
1138 // does user want us to display a specific channel?
1139 const dt_dev_pixelpipe_display_mask_t request_mask_display
1140 = (self->dev->gui_attached && (self == self->dev->gui_module) && (pipe == self->dev->pipe)
1141 && preview_mask_mode)
1142 ? self->request_mask_display
1144
1145 // get channel max values depending on colorspace
1146 const dt_develop_blend_colorspace_t blend_csp = d->blend_cst;
1148
1149 // obtaining the list of mask operations to perform
1150 _develop_mask_post_processing post_operations[3];
1151 const size_t post_operations_size = _develop_mask_get_post_operations(d, piece, post_operations);
1152
1153 // get the clipped opacity value 0 - 1
1154 const float opacity = fminf(fmaxf(d->opacity / 100.0f, 0.0f), 1.0f);
1155 const gboolean use_masks = raster_used || drawn_used || parametric_used;
1156 const gboolean raster_only = raster_used && !drawn_used && !parametric_used;
1157
1158 // allocate space for blend mask
1159 float *_mask = dt_pixelpipe_cache_alloc_align_float(buffsize, pipe);
1160 if(IS_NULL_PTR(_mask))
1161 {
1162 dt_control_log(_("could not allocate buffer for blending"));
1163 return 1;
1164 }
1165 float *const mask = _mask;
1166
1167 // setup some kernels
1168 int kernel_mask;
1169 int kernel;
1170 switch(blend_csp)
1171 {
1175 break;
1176
1180 break;
1181
1185 break;
1186
1188 default:
1191 break;
1192 }
1193 int kernel_mask_tone_curve = darktable.opencl->blendop->kernel_blendop_mask_tone_curve;
1194 int kernel_set_mask = darktable.opencl->blendop->kernel_blendop_set_mask;
1195 int kernel_display_channel = darktable.opencl->blendop->kernel_blendop_display_channel;
1196
1197 const int devid = pipe->devid;
1198 const int offs[2] = { xoffs, yoffs };
1199 const size_t sizes[] = { ROUNDUPDWD(owidth, devid), ROUNDUPDHT(oheight, devid), 1 };
1200
1201 cl_int err = -999;
1202 cl_mem dev_blendif_params = NULL;
1203 cl_mem dev_boost_factors = NULL;
1204 cl_mem dev_mask_1 = NULL;
1205 cl_mem dev_mask_2 = NULL;
1206 cl_mem dev_tmp = NULL;
1207 cl_mem dev_guide = NULL;
1208
1209 cl_mem dev_profile_info = NULL;
1210 cl_mem dev_profile_lut = NULL;
1211 dt_colorspaces_iccprofile_info_cl_t *profile_info_cl = NULL;
1212 cl_float *profile_lut_cl = NULL;
1213
1214 cl_mem dev_work_profile_info = NULL;
1215 cl_mem dev_work_profile_lut = NULL;
1216 dt_colorspaces_iccprofile_info_cl_t *work_profile_info_cl = NULL;
1217 cl_float *work_profile_lut_cl = NULL;
1218
1219 size_t origin[] = { 0, 0, 0 };
1220 size_t region[] = { owidth, oheight, 1 };
1221
1222 // parameters, for every channel the 4 limits + pre-computed increasing slope and decreasing slope
1225
1226 // copy blend parameters to constant device memory
1227 dev_blendif_params = dt_opencl_copy_host_to_device_constant(devid, sizeof(parameters), parameters);
1228 if(IS_NULL_PTR(dev_blendif_params)) goto error;
1229
1230 dev_mask_1 = dt_opencl_alloc_device(devid, owidth, oheight, sizeof(float));
1231 if(IS_NULL_PTR(dev_mask_1)) goto error;
1232
1234 const int use_profile = dt_develop_blendif_init_masking_profile(pipe, piece, &profile, blend_csp);
1235
1236 err = dt_ioppr_build_iccprofile_params_cl(use_profile ? &profile : NULL, devid, &profile_info_cl,
1237 &profile_lut_cl, &dev_profile_info, &dev_profile_lut);
1238 if(err != CL_SUCCESS) goto error;
1239
1240 if(!use_masks)
1241 {
1242 // blend uniformly (no drawn or parametric mask)
1243
1244 // set dev_mask with global opacity value
1245 dt_opencl_set_kernel_arg(devid, kernel_set_mask, 0, sizeof(cl_mem), (void *)&dev_mask_1);
1246 dt_opencl_set_kernel_arg(devid, kernel_set_mask, 1, sizeof(int), (void *)&owidth);
1247 dt_opencl_set_kernel_arg(devid, kernel_set_mask, 2, sizeof(int), (void *)&oheight);
1248 dt_opencl_set_kernel_arg(devid, kernel_set_mask, 3, sizeof(float), (void *)&opacity);
1249 err = dt_opencl_enqueue_kernel_2d(devid, kernel_set_mask, sizes);
1250 if(err != CL_SUCCESS) goto error;
1251 }
1252 else if(raster_only)
1253 {
1254 int raster_error = 0;
1255 _develop_blend_init_raster_mask(d, self, pipe, piece, mask, owidth, oheight, &raster_error);
1256 if(raster_error) goto error;
1257 dt_iop_image_mul_const(mask, opacity, owidth, oheight, 1);
1258
1259 err = dt_opencl_write_host_to_device(devid, mask, dev_mask_1, owidth, oheight, sizeof(float));
1260 if(err != CL_SUCCESS) goto error;
1261 }
1262 else
1263 {
1264 if(!raster_used && !drawn_used)
1265 {
1266 // Parametric-only blending has no raster/drawn form mask to seed `mask`.
1267 // The OpenCL mask kernel reads that form mask from `dev_mask_1`, so keep
1268 // the CPU staging buffer explicit and initialized before upload.
1269 const float fill = (d->mask_combine & DEVELOP_COMBINE_INCL) ? 0.0f : 1.0f;
1270 dt_iop_image_fill(mask, fill, owidth, oheight, 1);
1271 }
1272 else if(raster_used)
1273 {
1274 int raster_error = 0;
1275 _develop_blend_init_raster_mask(d, self, pipe, piece, mask, owidth, oheight, &raster_error);
1276 if(raster_error) goto error;
1277
1278 if(drawn_used)
1279 {
1280 float *const restrict drawn_mask = dt_pixelpipe_cache_alloc_align_float(buffsize, pipe);
1281 if(IS_NULL_PTR(drawn_mask)) goto error;
1282
1283 if(_develop_blend_init_drawn_mask(d, self, pipe, piece, roi_out, drawn_mask, owidth, oheight) != 0)
1284 {
1286 goto error;
1287 }
1288
1289 _develop_blend_combine_masks(mask, drawn_mask, buffsize);
1291 }
1292 }
1293 else if(drawn_used
1294 && _develop_blend_init_drawn_mask(d, self, pipe, piece, roi_out, mask, owidth, oheight) != 0)
1295 {
1296 goto error;
1297 }
1298 _refine_with_detail_mask_cl(self, pipe, piece, mask, d->details, devid);
1299
1300 // write mask from host to device
1301 dev_mask_2 = dt_opencl_alloc_device(devid, owidth, oheight, sizeof(float));
1302 if(IS_NULL_PTR(dev_mask_2)) goto error;
1303 err = dt_opencl_write_host_to_device(devid, mask, dev_mask_1, owidth, oheight, sizeof(float));
1304 if(err != CL_SUCCESS) goto error;
1305
1306 // get parametric mask (if any) and apply global opacity
1307 const unsigned blendif = d->blendif;
1308 const unsigned int mask_combine = d->mask_combine;
1309 dt_opencl_set_kernel_arg(devid, kernel_mask, 0, sizeof(cl_mem), (void *)&dev_in);
1310 dt_opencl_set_kernel_arg(devid, kernel_mask, 1, sizeof(cl_mem), (void *)&dev_out);
1311 dt_opencl_set_kernel_arg(devid, kernel_mask, 2, sizeof(cl_mem), (void *)&dev_mask_1);
1312 dt_opencl_set_kernel_arg(devid, kernel_mask, 3, sizeof(cl_mem), (void *)&dev_mask_2);
1313 dt_opencl_set_kernel_arg(devid, kernel_mask, 4, sizeof(int), (void *)&owidth);
1314 dt_opencl_set_kernel_arg(devid, kernel_mask, 5, sizeof(int), (void *)&oheight);
1315 dt_opencl_set_kernel_arg(devid, kernel_mask, 6, sizeof(float), (void *)&opacity);
1316 dt_opencl_set_kernel_arg(devid, kernel_mask, 7, sizeof(unsigned), (void *)&blendif);
1317 dt_opencl_set_kernel_arg(devid, kernel_mask, 8, sizeof(cl_mem), (void *)&dev_blendif_params);
1318 dt_opencl_set_kernel_arg(devid, kernel_mask, 9, sizeof(unsigned), (void *)&mask_mode);
1319 dt_opencl_set_kernel_arg(devid, kernel_mask, 10, sizeof(unsigned), (void *)&mask_combine);
1320 dt_opencl_set_kernel_arg(devid, kernel_mask, 11, 2 * sizeof(int), (void *)&offs);
1321 dt_opencl_set_kernel_arg(devid, kernel_mask, 12, sizeof(cl_mem), (void *)&dev_profile_info);
1322 dt_opencl_set_kernel_arg(devid, kernel_mask, 13, sizeof(cl_mem), (void *)&dev_profile_lut);
1323 dt_opencl_set_kernel_arg(devid, kernel_mask, 14, sizeof(int), (void *)&use_profile);
1324 err = dt_opencl_enqueue_kernel_2d(devid, kernel_mask, sizes);
1325 if(err != CL_SUCCESS)
1326 {
1327 fprintf(stderr, "[dt_develop_blend_process_cl] error %i enqueue kernel\n", err);
1328 goto error;
1329 }
1330
1331 // the mask is now located in dev_mask_2, put it in dev_mask_1
1332 _blend_process_cl_exchange(&dev_mask_1, &dev_mask_2);
1333
1334 // post processing the mask (it will always be stored in dev_mask_1)
1335 for(size_t index = 0; index < post_operations_size; ++index)
1336 {
1337 _develop_mask_post_processing operation = post_operations[index];
1338 if(operation == DEVELOP_MASK_POST_FEATHER_IN)
1339 {
1340 int w = (int)(2 * d->feathering_radius * roi_out->scale + 0.5f);
1341 if (w < 1) w = 1;
1342 const float sqrt_eps = 1.0f;
1343 const float guide_weight = dt_iop_colorspace_is_rgb(cst) ? 100.0f : 1.0f;
1344
1345 cl_mem guide = dev_in;
1346 if(!rois_equal)
1347 {
1348 dev_guide = dt_opencl_alloc_device(devid, owidth, oheight, sizeof(float) * 4);
1349 if(IS_NULL_PTR(dev_guide)) goto error;
1350 guide = dev_guide;
1351 size_t origin_1[] = { xoffs, yoffs, 0 };
1352 size_t origin_2[] = { 0, 0, 0 };
1353 err = dt_opencl_enqueue_copy_image(devid, dev_in, guide, origin_2, origin_1, region);
1354 if(err != CL_SUCCESS) goto error;
1355 }
1356 if(guided_filter_cl(devid, guide, dev_mask_1, dev_mask_2, owidth, oheight, ch, w, sqrt_eps, guide_weight,
1357 0.0f, 1.0f) != 0)
1358 goto error;
1359 if(!rois_equal)
1360 {
1362 dev_guide = NULL;
1363 }
1364 _blend_process_cl_exchange(&dev_mask_1, &dev_mask_2);
1365 }
1366 else if(operation == DEVELOP_MASK_POST_FEATHER_OUT)
1367 {
1368 int w = (int)(2 * d->feathering_radius * roi_out->scale + 0.5f);
1369 if (w < 1) w = 1;
1370 const float sqrt_eps = 1.0f;
1371 const float guide_weight = dt_iop_colorspace_is_rgb(cst) ? 100.0f : 1.0f;
1372
1373 if(guided_filter_cl(devid, dev_out, dev_mask_1, dev_mask_2, owidth, oheight, ch, w, sqrt_eps, guide_weight,
1374 0.0f, 1.0f) != 0)
1375 goto error;
1376 _blend_process_cl_exchange(&dev_mask_1, &dev_mask_2);
1377 }
1378 else if(operation == DEVELOP_MASK_POST_BLUR)
1379 {
1380 const float sigma = d->blur_radius * roi_out->scale;
1381 const float mmax[] = { 1.0f };
1382 const float mmin[] = { 0.0f };
1383
1384 dt_gaussian_cl_t *g = dt_gaussian_init_cl(devid, owidth, oheight, 1, mmax, mmin, sigma, 0);
1385 if(IS_NULL_PTR(g)) goto error;
1386 err = dt_gaussian_blur_cl(g, dev_mask_1, dev_mask_2);
1388 if(err != CL_SUCCESS) goto error;
1389 _blend_process_cl_exchange(&dev_mask_1, &dev_mask_2);
1390 }
1391 else if(operation == DEVELOP_MASK_POST_TONE_CURVE)
1392 {
1393 const float e = expf(3.f * d->contrast);
1394 const float brightness = d->brightness;
1395 dt_opencl_set_kernel_arg(devid, kernel_mask_tone_curve, 0, sizeof(cl_mem), (void *)&dev_mask_1);
1396 dt_opencl_set_kernel_arg(devid, kernel_mask_tone_curve, 1, sizeof(cl_mem), (void *)&dev_mask_2);
1397 dt_opencl_set_kernel_arg(devid, kernel_mask_tone_curve, 2, sizeof(int), (void *)&owidth);
1398 dt_opencl_set_kernel_arg(devid, kernel_mask_tone_curve, 3, sizeof(int), (void *)&oheight);
1399 dt_opencl_set_kernel_arg(devid, kernel_mask_tone_curve, 4, sizeof(float), (void *)&e);
1400 dt_opencl_set_kernel_arg(devid, kernel_mask_tone_curve, 5, sizeof(float), (void *)&brightness);
1401 dt_opencl_set_kernel_arg(devid, kernel_mask_tone_curve, 6, sizeof(float), (void *)&opacity);
1402 err = dt_opencl_enqueue_kernel_2d(devid, kernel_mask_tone_curve, sizes);
1403 if(err != CL_SUCCESS) goto error;
1404 _blend_process_cl_exchange(&dev_mask_1, &dev_mask_2);
1405 }
1406 }
1407
1408 // get rid of dev_mask_2
1409 dt_opencl_release_mem_object(dev_mask_2);
1410 dev_mask_2 = NULL;
1411 }
1412
1413 // get temporary buffer for output image to overcome readonly/writeonly limitation
1414 dev_tmp = dt_opencl_alloc_device(devid, owidth, oheight, sizeof(float) * 4);
1415 if(IS_NULL_PTR(dev_tmp)) goto error;
1416
1417 err = dt_opencl_enqueue_copy_image(devid, dev_out, dev_tmp, origin, origin, region);
1418 if(err != CL_SUCCESS) goto error;
1419
1420 if(request_mask_display & DT_DEV_PIXELPIPE_DISPLAY_ANY)
1421 {
1422 // load the boost factors in the device memory
1423 dev_boost_factors = dt_opencl_copy_host_to_device_constant(devid, sizeof(d->blendif_boost_factors),
1424 d->blendif_boost_factors);
1425 if(IS_NULL_PTR(dev_boost_factors)) goto error;
1426
1427 // the display channel of Lab blending is generated in RGB and should be transformed to Lab
1428 // the transformation in the pipeline is currently always using the work profile
1430 const int use_work_profile = !IS_NULL_PTR(work_profile);
1431
1432 err = dt_ioppr_build_iccprofile_params_cl(work_profile, devid, &work_profile_info_cl, &work_profile_lut_cl,
1433 &dev_work_profile_info, &dev_work_profile_lut);
1434 if(err != CL_SUCCESS) goto error;
1435
1436 // let us display a specific channel
1437 dt_opencl_set_kernel_arg(devid, kernel_display_channel, 0, sizeof(cl_mem), (void *)&dev_in);
1438 dt_opencl_set_kernel_arg(devid, kernel_display_channel, 1, sizeof(cl_mem), (void *)&dev_tmp);
1439 dt_opencl_set_kernel_arg(devid, kernel_display_channel, 2, sizeof(cl_mem), (void *)&dev_mask_1);
1440 dt_opencl_set_kernel_arg(devid, kernel_display_channel, 3, sizeof(cl_mem), (void *)&dev_out);
1441 dt_opencl_set_kernel_arg(devid, kernel_display_channel, 4, sizeof(int), (void *)&owidth);
1442 dt_opencl_set_kernel_arg(devid, kernel_display_channel, 5, sizeof(int), (void *)&oheight);
1443 dt_opencl_set_kernel_arg(devid, kernel_display_channel, 6, 2 * sizeof(int), (void *)&offs);
1444 dt_opencl_set_kernel_arg(devid, kernel_display_channel, 7, sizeof(int), (void *)&request_mask_display);
1445 dt_opencl_set_kernel_arg(devid, kernel_display_channel, 8, sizeof(cl_mem), (void*)&dev_boost_factors);
1446 dt_opencl_set_kernel_arg(devid, kernel_display_channel, 9, sizeof(cl_mem), (void *)&dev_profile_info);
1447 dt_opencl_set_kernel_arg(devid, kernel_display_channel, 10, sizeof(cl_mem), (void *)&dev_profile_lut);
1448 dt_opencl_set_kernel_arg(devid, kernel_display_channel, 11, sizeof(int), (void *)&use_profile);
1449 dt_opencl_set_kernel_arg(devid, kernel_display_channel, 12, sizeof(cl_mem), (void *)&dev_work_profile_info);
1450 dt_opencl_set_kernel_arg(devid, kernel_display_channel, 13, sizeof(cl_mem), (void *)&dev_work_profile_lut);
1451 dt_opencl_set_kernel_arg(devid, kernel_display_channel, 14, sizeof(int), (void *)&use_work_profile);
1452 err = dt_opencl_enqueue_kernel_2d(devid, kernel_display_channel, sizes);
1453 if(err != CL_SUCCESS)
1454 {
1455 fprintf(stderr, "[dt_develop_blend_process_cl] error %i enqueue kernel\n", err);
1456 goto error;
1457 }
1458 }
1459 else
1460 {
1461 // apply blending with per-pixel opacity value as defined in dev_mask_1
1462 const unsigned int blend_mode = d->blend_mode;
1463 const float blend_parameter = exp2f(d->blend_parameter);
1464 dt_opencl_set_kernel_arg(devid, kernel, 0, sizeof(cl_mem), (void *)&dev_in);
1465 dt_opencl_set_kernel_arg(devid, kernel, 1, sizeof(cl_mem), (void *)&dev_tmp);
1466 dt_opencl_set_kernel_arg(devid, kernel, 2, sizeof(cl_mem), (void *)&dev_mask_1);
1467 dt_opencl_set_kernel_arg(devid, kernel, 3, sizeof(cl_mem), (void *)&dev_out);
1468 dt_opencl_set_kernel_arg(devid, kernel, 4, sizeof(int), (void *)&owidth);
1469 dt_opencl_set_kernel_arg(devid, kernel, 5, sizeof(int), (void *)&oheight);
1470 dt_opencl_set_kernel_arg(devid, kernel, 6, sizeof(unsigned), (void *)&blend_mode);
1471 dt_opencl_set_kernel_arg(devid, kernel, 7, sizeof(float), (void *)&blend_parameter);
1472 dt_opencl_set_kernel_arg(devid, kernel, 8, 2 * sizeof(int), (void *)&offs);
1473 dt_opencl_set_kernel_arg(devid, kernel, 9, sizeof(int), (void *)&mask_display);
1474 err = dt_opencl_enqueue_kernel_2d(devid, kernel, sizes);
1475 if(err != CL_SUCCESS) goto error;
1476 }
1477
1478 // register if _this_ module should expose mask or display channel
1480 {
1481 pipe->mask_display = request_mask_display;
1482 }
1483
1484
1485 // check if we should store the mask for export or use in subsequent modules
1487 {
1488 // get back final mask from the device to store it for later use
1489 if(!raster_only)
1490 {
1491 err = dt_opencl_copy_device_to_host(devid, mask, dev_mask_1, owidth, oheight, sizeof(float));
1492 if(err != CL_SUCCESS) goto error;
1493 }
1494
1495 const uint64_t mask_hash = dt_dev_pixelpipe_raster_mask_hash(piece, 0);
1496 dt_pixel_cache_entry_t *mask_entry = NULL;
1497 void *cache_data = NULL;
1498 const int created = dt_dev_pixelpipe_cache_get(
1499 darktable.pixelpipe_cache, mask_hash, sizeof(float) * buffsize,
1500 "raster mask", pipe->type, TRUE, &cache_data, &mask_entry);
1501
1502 if(IS_NULL_PTR(cache_data) || IS_NULL_PTR(mask_entry))
1503 {
1504 if(created && !IS_NULL_PTR(mask_entry))
1506 if(!IS_NULL_PTR(mask_entry))
1507 {
1509 if(created)
1511 }
1512 goto error;
1513 }
1514
1515 // The OpenCL mask has been materialized into `_mask` above. Publish that
1516 // host payload once so CPU and GPU consumers share the same cache entry.
1517 if(created)
1518 {
1519 memcpy(cache_data, _mask, sizeof(float) * buffsize);
1521 }
1522 // Transfer cache_get()'s reference to the pipe. It keeps this side-band
1523 // output alive until the next graph state is prepared or the pipe closes.
1524 g_array_append_val(pipe->raster_mask_hashes, mask_hash);
1526 _mask = NULL;
1527
1529 "[raster masks] %s mask id 0 for module %s (%s) for pipe %s"
1530 " with cache hash %" PRIu64 "\n",
1531 created ? "published" : "reused cached",
1532 piece->module->op, piece->module->multi_name,
1533 dt_pipe_type_to_str(pipe->type), mask_hash);
1534 }
1535 else
1536 {
1538 "[raster masks] discarding unpublished mask id 0 for module %s (%s) for pipe %s\n",
1539 piece->module->op, piece->module->multi_name,
1540 dt_pipe_type_to_str(pipe->type));
1542 }
1543
1544 dt_opencl_release_mem_object(dev_blendif_params);
1545 dt_opencl_release_mem_object(dev_boost_factors);
1546 dt_opencl_release_mem_object(dev_mask_1);
1548 dt_ioppr_free_iccprofile_params_cl(&profile_info_cl, &profile_lut_cl, &dev_profile_info, &dev_profile_lut);
1549 dt_ioppr_free_iccprofile_params_cl(&work_profile_info_cl, &work_profile_lut_cl, &dev_work_profile_info,
1550 &dev_work_profile_lut);
1551 return 0;
1552
1553error:
1555 dt_opencl_release_mem_object(dev_blendif_params);
1556 dt_opencl_release_mem_object(dev_boost_factors);
1557 dt_opencl_release_mem_object(dev_mask_1);
1558 dt_opencl_release_mem_object(dev_mask_2);
1561 if(profile_info_cl) dt_ioppr_free_iccprofile_params_cl(&profile_info_cl, &profile_lut_cl, &dev_profile_info, &dev_profile_lut);
1562 if(work_profile_info_cl) dt_ioppr_free_iccprofile_params_cl(&work_profile_info_cl, &work_profile_lut_cl, &dev_work_profile_info,
1563 &dev_work_profile_lut);
1564 dt_print(DT_DEBUG_OPENCL, "[opencl_blendop] couldn't enqueue kernel! %d\n", err);
1565 return 1;
1566}
1567#endif
1568
1571{
1572#ifdef HAVE_OPENCL
1574
1575 const int program = 3; // blendop.cl, from programs.conf
1576 b->kernel_blendop_mask_Lab = dt_opencl_create_kernel(program, "blendop_mask_Lab");
1577 b->kernel_blendop_mask_RAW = dt_opencl_create_kernel(program, "blendop_mask_RAW");
1578 b->kernel_blendop_mask_rgb_hsl = dt_opencl_create_kernel(program, "blendop_mask_rgb_hsl");
1579 b->kernel_blendop_mask_rgb_jzczhz = dt_opencl_create_kernel(program, "blendop_mask_rgb_jzczhz");
1580 b->kernel_blendop_Lab = dt_opencl_create_kernel(program, "blendop_Lab");
1581 b->kernel_blendop_RAW = dt_opencl_create_kernel(program, "blendop_RAW");
1582 b->kernel_blendop_rgb_hsl = dt_opencl_create_kernel(program, "blendop_rgb_hsl");
1583 b->kernel_blendop_rgb_jzczhz = dt_opencl_create_kernel(program, "blendop_rgb_jzczhz");
1584 b->kernel_blendop_mask_tone_curve = dt_opencl_create_kernel(program, "blendop_mask_tone_curve");
1585 b->kernel_blendop_set_mask = dt_opencl_create_kernel(program, "blendop_set_mask");
1586 b->kernel_blendop_display_channel = dt_opencl_create_kernel(program, "blendop_display_channel");
1587
1588 const int program_rcd = 31;
1589 b->kernel_calc_Y0_mask = dt_opencl_create_kernel(program_rcd, "calc_Y0_mask");
1590 b->kernel_calc_scharr_mask = dt_opencl_create_kernel(program_rcd, "calc_scharr_mask");
1591 b->kernel_write_mask = dt_opencl_create_kernel(program_rcd, "writeout_mask");
1592 b->kernel_read_mask = dt_opencl_create_kernel(program_rcd, "readin_mask");
1593 b->kernel_calc_blend = dt_opencl_create_kernel(program_rcd, "calc_detail_blend");
1594 b->kernel_mask_blur = dt_opencl_create_kernel(program_rcd, "fastblur_mask_9x9");
1595
1596 return b;
1597#else
1598 return NULL;
1599#endif
1600}
1601
1604{
1605#ifdef HAVE_OPENCL
1606 if(IS_NULL_PTR(b)) return;
1607
1608 dt_opencl_free_kernel(b->kernel_blendop_mask_Lab);
1609 dt_opencl_free_kernel(b->kernel_blendop_mask_RAW);
1610 dt_opencl_free_kernel(b->kernel_blendop_mask_rgb_hsl);
1611 dt_opencl_free_kernel(b->kernel_blendop_mask_rgb_jzczhz);
1612 dt_opencl_free_kernel(b->kernel_blendop_Lab);
1613 dt_opencl_free_kernel(b->kernel_blendop_RAW);
1614 dt_opencl_free_kernel(b->kernel_blendop_rgb_hsl);
1615 dt_opencl_free_kernel(b->kernel_blendop_rgb_jzczhz);
1616 dt_opencl_free_kernel(b->kernel_blendop_mask_tone_curve);
1617 dt_opencl_free_kernel(b->kernel_blendop_set_mask);
1618 dt_opencl_free_kernel(b->kernel_blendop_display_channel);
1619 dt_opencl_free_kernel(b->kernel_calc_Y0_mask);
1620 dt_opencl_free_kernel(b->kernel_calc_scharr_mask);
1621 dt_opencl_free_kernel(b->kernel_write_mask);
1622 dt_opencl_free_kernel(b->kernel_read_mask);
1623 dt_opencl_free_kernel(b->kernel_calc_blend);
1624 dt_opencl_free_kernel(b->kernel_mask_blur);
1625 dt_free(b);
1626#endif
1627}
1628
1631{
1632 return DEVELOP_BLEND_VERSION;
1633}
1634
1636void tiling_callback_blendop(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe,
1637 const struct dt_dev_pixelpipe_iop_t *piece, struct dt_develop_tiling_t *tiling)
1638{
1639 tiling->factor = 3.5f; // in + out + (guide, tmp) + two quarter buffers for the mask
1640 tiling->maxbuf = 1.0f;
1641 tiling->overhead = 0;
1642 tiling->overlap = 0;
1643 tiling->xalign = 1;
1644 tiling->yalign = 1;
1645
1647 if(!IS_NULL_PTR(bldata))
1648 {
1649 if(bldata->details != 0.0f)
1650 tiling->factor += 0.75f; // details mask requires 3 additional quarter buffers
1651 }
1652}
1653
1657gboolean dt_develop_blend_params_is_all_zero(const void *params, size_t length)
1658{
1659 const char *data = (const char *)params;
1660
1661 for(size_t k = 0; k < length; k++)
1662 if(data[k]) return FALSE;
1663
1664 return TRUE;
1665}
1666
1667static uint32_t _blend_legacy_blend_mode(uint32_t legacy_blend_mode)
1668{
1669 uint32_t blend_mode = legacy_blend_mode & DEVELOP_BLEND_MODE_MASK;
1670 gboolean blend_reverse = FALSE;
1671 switch(blend_mode) {
1673 blend_mode = DEVELOP_BLEND_BOUNDED;
1674 break;
1676 blend_mode = DEVELOP_BLEND_BOUNDED;
1677 blend_reverse = TRUE;
1678 break;
1681 blend_mode = DEVELOP_BLEND_NORMAL2;
1682 break;
1684 blend_mode = DEVELOP_BLEND_MULTIPLY;
1685 blend_reverse = TRUE;
1686 break;
1687 default:
1688 break;
1689 }
1690 return (blend_reverse ? DEVELOP_BLEND_REVERSE : 0) | blend_mode;
1691}
1692
1694int dt_develop_blend_legacy_params(dt_iop_module_t *module, const void *const old_params,
1695 const int old_version, void *new_params, const int new_version,
1696 const int length)
1697{
1698 // edits before version 10 default to a display referred workflow
1700
1701 dt_develop_blend_params_t default_display_blend_params;
1702 dt_develop_blend_init_blend_parameters(&default_display_blend_params, cst);
1703
1704 // first deal with all-zero parameter sets, regardless of version number.
1705 // these occurred in previous darktable versions when modules without blend support stored zero-initialized data
1706 // in history stack. that's no problem unless the module gets blend support later (e.g. module exposure).
1707 // remedy: we simply initialize with the current default blend params in this case.
1708 if(dt_develop_blend_params_is_all_zero(old_params, length))
1709 {
1711
1712 *n = default_display_blend_params;
1713 return 0;
1714 }
1715
1716 if(old_version == 1 && new_version == 11)
1717 {
1719 typedef struct dt_develop_blend_params1_t
1720 {
1721 uint32_t mode;
1722 float opacity;
1723 uint32_t mask_id;
1724 } dt_develop_blend_params1_t;
1725
1726 if(length != sizeof(dt_develop_blend_params1_t)) return 1;
1727
1728 dt_develop_blend_params1_t *o = (dt_develop_blend_params1_t *)old_params;
1730
1731 *n = default_display_blend_params; // start with a fresh copy of default parameters
1733 n->blend_mode = _blend_legacy_blend_mode(o->mode);
1734 n->opacity = o->opacity;
1735 n->mask_id = o->mask_id;
1736 return 0;
1737 }
1738
1739 if(old_version == 2 && new_version == 11)
1740 {
1742 typedef struct dt_develop_blend_params2_t
1743 {
1745 uint32_t mode;
1747 float opacity;
1749 uint32_t mask_id;
1751 uint32_t blendif;
1753 float blendif_parameters[4 * 8];
1754 } dt_develop_blend_params2_t;
1755
1756 if(length != sizeof(dt_develop_blend_params2_t)) return 1;
1757
1758 dt_develop_blend_params2_t *o = (dt_develop_blend_params2_t *)old_params;
1760
1761 *n = default_display_blend_params; // start with a fresh copy of default parameters
1763 n->mask_mode |= ((o->blendif & (1u << DEVELOP_BLENDIF_active)) && (n->mask_mode == DEVELOP_MASK_ENABLED))
1765 : 0;
1766 n->blend_mode = _blend_legacy_blend_mode(o->mode);
1767 n->opacity = o->opacity;
1768 n->mask_id = o->mask_id;
1769 n->blendif = o->blendif & 0xff; // only just in case: knock out all bits
1770 // which were undefined in version
1771 // 2; also switch off old "active" bit
1772 for(int i = 0; i < (4 * 8); i++) n->blendif_parameters[i] = o->blendif_parameters[i];
1773
1774 return 0;
1775 }
1776
1777 if(old_version == 3 && new_version == 11)
1778 {
1780 typedef struct dt_develop_blend_params3_t
1781 {
1783 uint32_t mode;
1785 float opacity;
1787 uint32_t mask_id;
1789 uint32_t blendif;
1791 float blendif_parameters[4 * DEVELOP_BLENDIF_SIZE];
1792 } dt_develop_blend_params3_t;
1793
1794 if(length != sizeof(dt_develop_blend_params3_t)) return 1;
1795
1796 dt_develop_blend_params3_t *o = (dt_develop_blend_params3_t *)old_params;
1798
1799 *n = default_display_blend_params; // start with a fresh copy of default parameters
1801 n->mask_mode |= ((o->blendif & (1u << DEVELOP_BLENDIF_active)) && (n->mask_mode == DEVELOP_MASK_ENABLED))
1803 : 0;
1804 n->blend_mode = _blend_legacy_blend_mode(o->mode);
1805 n->opacity = o->opacity;
1806 n->mask_id = o->mask_id;
1807 n->blendif = o->blendif & ~(1u << DEVELOP_BLENDIF_active); // knock out old unused "active" flag
1808 memcpy(n->blendif_parameters, o->blendif_parameters, sizeof(float) * 4 * DEVELOP_BLENDIF_SIZE);
1809
1810 return 0;
1811 }
1812
1813 if(old_version == 4 && new_version == 11)
1814 {
1816 typedef struct dt_develop_blend_params4_t
1817 {
1819 uint32_t mode;
1821 float opacity;
1823 uint32_t mask_id;
1825 uint32_t blendif;
1827 float radius;
1829 float blendif_parameters[4 * DEVELOP_BLENDIF_SIZE];
1830 } dt_develop_blend_params4_t;
1831
1832 if(length != sizeof(dt_develop_blend_params4_t)) return 1;
1833
1834 dt_develop_blend_params4_t *o = (dt_develop_blend_params4_t *)old_params;
1836
1837 *n = default_display_blend_params; // start with a fresh copy of default parameters
1839 n->mask_mode |= ((o->blendif & (1u << DEVELOP_BLENDIF_active)) && (n->mask_mode == DEVELOP_MASK_ENABLED))
1841 : 0;
1842 n->blend_mode = _blend_legacy_blend_mode(o->mode);
1843 n->opacity = o->opacity;
1844 n->mask_id = o->mask_id;
1845 n->blur_radius = o->radius;
1846 n->blendif = o->blendif & ~(1u << DEVELOP_BLENDIF_active); // knock out old unused "active" flag
1847 memcpy(n->blendif_parameters, o->blendif_parameters, sizeof(float) * 4 * DEVELOP_BLENDIF_SIZE);
1848
1849 return 0;
1850 }
1851
1852 if(old_version == 5 && new_version == 11)
1853 {
1855 typedef struct dt_develop_blend_params5_t
1856 {
1858 uint32_t mask_mode;
1860 uint32_t blend_mode;
1862 float opacity;
1864 uint32_t mask_combine;
1866 uint32_t mask_id;
1868 uint32_t blendif;
1870 float radius;
1872 uint32_t reserved[4];
1874 float blendif_parameters[4 * DEVELOP_BLENDIF_SIZE];
1875 } dt_develop_blend_params5_t;
1876
1877 if(length != sizeof(dt_develop_blend_params5_t)) return 1;
1878
1879 dt_develop_blend_params5_t *o = (dt_develop_blend_params5_t *)old_params;
1881
1882 *n = default_display_blend_params; // start with a fresh copy of default parameters
1883 n->mask_mode = o->mask_mode;
1884 n->blend_mode = _blend_legacy_blend_mode(o->blend_mode);
1885 n->opacity = o->opacity;
1886 n->mask_combine = o->mask_combine;
1887 n->mask_id = o->mask_id;
1888 n->blur_radius = o->radius;
1889 // this is needed as version 5 contained a bug which screwed up history
1890 // stacks of even older
1891 // versions. potentially bad history stacks can be identified by an active
1892 // bit no. 32 in blendif.
1893 n->blendif = (o->blendif & (1u << DEVELOP_BLENDIF_active) ? o->blendif | 31 : o->blendif)
1894 & ~(1u << DEVELOP_BLENDIF_active);
1895 memcpy(n->blendif_parameters, o->blendif_parameters, sizeof(float) * 4 * DEVELOP_BLENDIF_SIZE);
1896
1897 return 0;
1898 }
1899
1900 if(old_version == 6 && new_version == 11)
1901 {
1903 typedef struct dt_develop_blend_params6_t
1904 {
1906 uint32_t mask_mode;
1908 uint32_t blend_mode;
1910 float opacity;
1912 uint32_t mask_combine;
1914 uint32_t mask_id;
1916 uint32_t blendif;
1918 float radius;
1920 uint32_t reserved[4];
1922 float blendif_parameters[4 * DEVELOP_BLENDIF_SIZE];
1923 } dt_develop_blend_params6_t;
1924
1925 if(length != sizeof(dt_develop_blend_params6_t)) return 1;
1926
1927 dt_develop_blend_params6_t *o = (dt_develop_blend_params6_t *)old_params;
1929
1930 *n = default_display_blend_params; // start with a fresh copy of default parameters
1931 n->mask_mode = o->mask_mode;
1932 n->blend_mode = _blend_legacy_blend_mode(o->blend_mode);
1933 n->opacity = o->opacity;
1934 n->mask_combine = o->mask_combine;
1935 n->mask_id = o->mask_id;
1936 n->blur_radius = o->radius;
1937 n->blendif = o->blendif;
1938 memcpy(n->blendif_parameters, o->blendif_parameters, sizeof(float) * 4 * DEVELOP_BLENDIF_SIZE);
1939 return 0;
1940 }
1941
1942 if(old_version == 7 && new_version == 11)
1943 {
1945 typedef struct dt_develop_blend_params7_t
1946 {
1948 uint32_t mask_mode;
1950 uint32_t blend_mode;
1952 float opacity;
1954 uint32_t mask_combine;
1956 uint32_t mask_id;
1958 uint32_t blendif;
1960 float radius;
1962 uint32_t reserved[4];
1964 float blendif_parameters[4 * DEVELOP_BLENDIF_SIZE];
1965 } dt_develop_blend_params7_t;
1966
1967 if(length != sizeof(dt_develop_blend_params7_t)) return 1;
1968
1969 dt_develop_blend_params7_t *o = (dt_develop_blend_params7_t *)old_params;
1971
1972 *n = default_display_blend_params; // start with a fresh copy of default parameters
1973 n->mask_mode = o->mask_mode;
1974 n->blend_mode = _blend_legacy_blend_mode(o->blend_mode);
1975 n->opacity = o->opacity;
1976 n->mask_combine = o->mask_combine;
1977 n->mask_id = o->mask_id;
1978 n->blur_radius = o->radius;
1979 n->blendif = o->blendif;
1980 memcpy(n->blendif_parameters, o->blendif_parameters, sizeof(float) * 4 * DEVELOP_BLENDIF_SIZE);
1981 return 0;
1982 }
1983
1984 if(old_version == 8 && new_version == 11)
1985 {
1987 typedef struct dt_develop_blend_params8_t
1988 {
1990 uint32_t mask_mode;
1992 uint32_t blend_mode;
1994 float opacity;
1996 uint32_t mask_combine;
1998 uint32_t mask_id;
2000 uint32_t blendif;
2002 float feathering_radius;
2004 uint32_t feathering_guide;
2006 float blur_radius;
2008 float contrast;
2010 float brightness;
2012 uint32_t reserved[4];
2014 float blendif_parameters[4 * DEVELOP_BLENDIF_SIZE];
2015 } dt_develop_blend_params8_t;
2016
2017 if(length != sizeof(dt_develop_blend_params8_t)) return 1;
2018
2019 dt_develop_blend_params8_t *o = (dt_develop_blend_params8_t *)old_params;
2021
2022 *n = default_display_blend_params; // start with a fresh copy of default parameters
2023 n->mask_mode = o->mask_mode;
2024 n->blend_mode = _blend_legacy_blend_mode(o->blend_mode);
2025 n->opacity = o->opacity;
2026 n->mask_combine = o->mask_combine;
2027 n->mask_id = o->mask_id;
2028 n->blendif = o->blendif;
2029 n->feathering_radius = o->feathering_radius;
2030 n->feathering_guide = o->feathering_guide;
2031 n->blur_radius = o->blur_radius;
2032 n->contrast = o->contrast;
2033 n->brightness = o->brightness;
2034 memcpy(n->blendif_parameters, o->blendif_parameters, sizeof(float) * 4 * DEVELOP_BLENDIF_SIZE);
2035 return 0;
2036 }
2037
2038 if(old_version == 9 && new_version == 11)
2039 {
2041 typedef struct dt_develop_blend_params9_t
2042 {
2045 uint32_t mask_mode;
2047 uint32_t blend_mode;
2049 float opacity;
2051 uint32_t mask_combine;
2053 uint32_t mask_id;
2055 uint32_t blendif;
2057 float feathering_radius;
2059 uint32_t feathering_guide;
2061 float blur_radius;
2063 float contrast;
2065 float brightness;
2067 uint32_t reserved[4];
2069 float blendif_parameters[4 * DEVELOP_BLENDIF_SIZE];
2070 dt_dev_operation_t raster_mask_source;
2071 int raster_mask_instance;
2072 int raster_mask_id;
2073 gboolean raster_mask_invert;
2074 } dt_develop_blend_params9_t;
2075
2076 if(length != sizeof(dt_develop_blend_params9_t)) return 1;
2077
2078 dt_develop_blend_params9_t *o = (dt_develop_blend_params9_t *)old_params;
2080
2081 *n = default_display_blend_params; // start with a fresh copy of default parameters
2082 n->mask_mode = o->mask_mode;
2083 n->blend_mode = _blend_legacy_blend_mode(o->blend_mode);
2084 n->opacity = o->opacity;
2085 n->mask_combine = o->mask_combine;
2086 n->mask_id = o->mask_id;
2087 n->blendif = o->blendif;
2088 n->feathering_radius = o->feathering_radius;
2089 n->feathering_guide = o->feathering_guide;
2090 n->blur_radius = o->blur_radius;
2091 n->contrast = o->contrast;
2092 n->brightness = o->brightness;
2093 memcpy(n->blendif_parameters, o->blendif_parameters, sizeof(float) * 4 * DEVELOP_BLENDIF_SIZE);
2094 memcpy(n->raster_mask_source, o->raster_mask_source, sizeof(n->raster_mask_source));
2095 n->raster_mask_instance = o->raster_mask_instance;
2096 n->raster_mask_id = o->raster_mask_id;
2097 n->raster_mask_invert = o->raster_mask_invert;
2098 return 0;
2099 }
2100
2101 if(old_version == 10 && new_version == 11)
2102 {
2104 typedef struct dt_develop_blend_params10_t
2105 {
2108 uint32_t mask_mode;
2110 int32_t blend_cst;
2112 uint32_t blend_mode;
2114 float blend_parameter;
2116 float opacity;
2118 uint32_t mask_combine;
2120 uint32_t mask_id;
2122 uint32_t blendif;
2124 float feathering_radius;
2126 uint32_t feathering_guide;
2128 float blur_radius;
2130 float contrast;
2132 float brightness;
2134 uint32_t reserved[4];
2136 float blendif_parameters[4 * DEVELOP_BLENDIF_SIZE];
2137 float blendif_boost_factors[DEVELOP_BLENDIF_SIZE];
2138 dt_dev_operation_t raster_mask_source;
2139 int raster_mask_instance;
2140 int raster_mask_id;
2141 gboolean raster_mask_invert;
2142 } dt_develop_blend_params10_t;
2143
2144 if(length != sizeof(dt_develop_blend_params10_t)) return 1;
2145
2146 dt_develop_blend_params10_t *o = (dt_develop_blend_params10_t *)old_params;
2148
2149 *n = default_display_blend_params; // start with a fresh copy of default parameters
2150 n->mask_mode = o->mask_mode;
2151 n->blend_cst = o->blend_cst;
2152 n->blend_mode = _blend_legacy_blend_mode(o->blend_mode);
2153 n->blend_parameter = o->blend_parameter;
2154 n->opacity = o->opacity;
2155 n->mask_combine = o->mask_combine;
2156 n->mask_id = o->mask_id;
2157 n->blendif = o->blendif;
2158 n->feathering_radius = o->feathering_radius;
2159 n->feathering_guide = o->feathering_guide;
2160 n->blur_radius = o->blur_radius;
2161 n->contrast = o->contrast;
2162 n->brightness = o->brightness;
2163 // fix intermediate devel versions for details mask and initialize n->details to proper values if something was wrong
2164 memcpy(&n->details, &o->reserved, sizeof(float));
2165 if(isnan(n->details)) n->details = 0.0f;
2166 n->details = fminf(1.0f, fmaxf(-1.0f, n->details));
2167
2168 memcpy(n->blendif_parameters, o->blendif_parameters, sizeof(float) * 4 * DEVELOP_BLENDIF_SIZE);
2169 memcpy(n->blendif_boost_factors, o->blendif_boost_factors, sizeof(float) * DEVELOP_BLENDIF_SIZE);
2170 memcpy(n->raster_mask_source, o->raster_mask_source, sizeof(n->raster_mask_source));
2171 n->raster_mask_instance = o->raster_mask_instance;
2172 n->raster_mask_id = o->raster_mask_id;
2173 n->raster_mask_invert = o->raster_mask_invert;
2174 return 0;
2175 }
2176
2177 return 1;
2178}
2179
2180int dt_develop_blend_legacy_params_from_so(dt_iop_module_so_t *module_so, const void *const old_params,
2181 const int old_version, void *new_params, const int new_version,
2182 const int length)
2183{
2184 // we need a dt_iop_module_t for dt_develop_blend_legacy_params()
2185 dt_iop_module_t *module = (dt_iop_module_t *)calloc(1, sizeof(dt_iop_module_t));
2186 if(dt_iop_load_module_by_so(module, module_so, NULL))
2187 {
2188 dt_free(module);
2189 return 1;
2190 }
2191
2192 if(module->params_size == 0)
2193 {
2194 dt_iop_cleanup_module(module);
2195 dt_free(module);
2196 return 1;
2197 }
2198
2199 // convert the old blend params to new
2200 const int res = dt_develop_blend_legacy_params(module, old_params, old_version,
2201 new_params, dt_develop_blend_version(),
2202 length);
2203 dt_iop_cleanup_module(module);
2204 dt_free(module);
2205 return res;
2206}
2207
2208// tools/update_modelines.sh
2209// remove-trailing-space on;
2210// clang-format off
2211// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
2212// vim: shiftwidth=2 expandtab tabstop=2 cindent
2213// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
2214// 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:108
_develop_mask_post_processing
Definition blend.c:60
@ DEVELOP_MASK_POST_TONE_CURVE
Definition blend.c:65
@ DEVELOP_MASK_POST_FEATHER_IN
Definition blend.c:63
@ DEVELOP_MASK_POST_FEATHER_OUT
Definition blend.c:64
@ DEVELOP_MASK_POST_BLUR
Definition blend.c:62
@ DEVELOP_MASK_POST_NONE
Definition blend.c:61
void dt_develop_blend_init_blend_parameters(dt_develop_blend_params_t *blend_params, dt_develop_blend_colorspace_t cst)
Definition blend.c:157
static void _develop_blend_combine_masks(float *const restrict mask, const float *const restrict other_mask, const size_t buffsize)
Definition blend.c:577
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:1087
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:505
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:941
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:411
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:455
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:1636
static uint32_t _blend_legacy_blend_mode(uint32_t legacy_blend_mode)
Definition blend.c:1667
dt_blendop_cl_global_t * dt_develop_blend_init_cl_global(void)
Definition blend.c:1570
void dt_develop_blendif_process_parameters(float *const restrict parameters, const dt_develop_blend_params_t *const params)
Definition blend.c:198
void dt_develop_blend_free_cl_global(dt_blendop_cl_global_t *b)
Definition blend.c:1603
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:179
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:306
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:2180
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:345
dt_develop_blend_colorspace_t dt_develop_blend_default_module_blend_colorspace(dt_iop_module_t *module)
Definition blend.c:135
int dt_develop_blend_version(void)
Definition blend.c:1630
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:1694
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:482
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:246
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:641
static void _blend_init_blendif_boost_parameters(dt_develop_blend_params_t *blend_params, dt_develop_blend_colorspace_t cst)
Definition blend.c:140
static const char * dt_pipe_type_to_str(dt_dev_pixelpipe_type_t pipe_type)
Definition blend.c:68
gboolean dt_develop_blend_params_is_all_zero(const void *params, size_t length)
Definition blend.c:1657
static dt_develop_blend_params_t _default_blendop_params
Definition blend.c:86
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:610
static void _develop_blend_process_free_region(float *const restrict input)
Definition blend.c:477
static float _detail_mask_threshold(const float level, const gboolean detail)
Definition blend.c:339
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:545
void dt_develop_blend_init_blendif_parameters(dt_develop_blend_params_t *blend_params, dt_develop_blend_colorspace_t cst)
Definition blend.c:165
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:587
static void _blend_process_cl_exchange(cl_mem *a, cl_mem *b)
Definition blend.c:1080
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:451
@ 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:761
darktable_t darktable
Definition darktable.c:181
void dt_print(dt_debug_thread_t thread, const char *msg,...)
Definition darktable.c:1542
@ DT_DEBUG_OPENCL
Definition darktable.h:722
@ DT_DEBUG_MASKS
Definition darktable.h:727
#define DT_ALIGNED_ARRAY
Definition darktable.h:388
#define dt_pixelpipe_cache_alloc_align_float_cache(pixels, id)
Definition darktable.h:447
#define dt_free(ptr)
Definition darktable.h:456
#define dt_pixelpipe_cache_free_align(mem)
Definition darktable.h:453
#define dt_pixelpipe_cache_alloc_align_float(pixels, pipe)
Definition darktable.h:442
#define __OMP_PARALLEL_FOR__(...)
Definition darktable.h:258
static const dt_aligned_pixel_simd_t value
Definition darktable.h:577
#define __OMP_FOR_SIMD__(...)
Definition darktable.h:260
#define __OMP_PARALLEL_FOR_SIMD__(...)
Definition darktable.h:259
#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:281
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:3067
void dt_iop_cleanup_module(dt_iop_module_t *module)
Definition imageop.c:1561
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:466
static gboolean dt_iop_colorspace_is_rgb(const dt_iop_colorspace_type_t cst)
Definition imageop.h:213
@ IOP_FLAGS_SUPPORTS_BLENDING
Definition imageop.h:167
@ IOP_FLAGS_NO_MASKS
Definition imageop.h:175
@ IOP_CS_RGB_DISPLAY
Definition imageop.h:210
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:133
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:2136
void * dt_opencl_alloc_device_buffer(const int devid, const size_t size)
Definition opencl.c:2544
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:2163
void * dt_opencl_alloc_device(const int devid, const int width, const int height, const int bpp)
Definition opencl.c:2471
int dt_opencl_create_kernel(const int prog, const char *name)
Definition opencl.c:2030
void * dt_opencl_copy_host_to_device_constant(const int devid, const size_t size, void *host)
Definition opencl.c:2332
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:2261
void dt_opencl_free_kernel(const int kernel)
Definition opencl.c:2073
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:2127
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:2169
void dt_opencl_release_mem_object(cl_mem mem)
Definition opencl.c:2383
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:2216
#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:790
struct dt_opencl_t * opencl
Definition darktable.h:785
int32_t unmuted
Definition darktable.h:760
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:279
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_iop_module_t::@31 raster_mask
struct dt_develop_t * dev
Definition imageop.h:296
struct dt_iop_module_t::@31::@32 source
GModule *dt_dev_operation_t op
Definition imageop.h:256
int request_mask_display
Definition imageop.h:268
struct dt_iop_module_t::@31::@33 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:378
GList * points
Definition masks.h:377
struct dt_blendop_cl_global_t * blendop
Definition opencl.h:251
#define MAX(a, b)
Definition thinplate.c:29
static const int mask_id
Definition useless.c:210