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*/
43#include "system/macros.h"
44#include "develop/iop_profile.h"
45#include "system/openmp.h"
46#include "system/mem_alloc.h"
47#include "common/logging.h"
49#include "blend.h"
50#include "pixel/gaussian.h"
51#include "pixel/guided_filter.h"
52#include "common/imagebuf.h"
53#include "common/opencl.h"
54#include "develop/imageop.h"
55#include "develop/masks.h"
58#include "develop/supervisor.h"
59#include "develop/tiling.h"
60#include <inttypes.h>
61#include <limits.h>
62#include <math.h>
63#include <string.h>
64
65/* The blend kernels, owned HERE. They used to be handed to common/opencl.c, parked on the
66 * application-wide dt_opencl_t, and read back from it by this file and by two IOPs -- a round
67 * trip through a god-struct that added nothing but an ordering. opencl.c still calls init and
68 * free, because the kernels must be built after the devices exist; the pointer itself no
69 * longer leaves the blend subsystem except through dt_develop_blend_get_cl_global(). */
71
76
85
86static const char *dt_pipe_type_to_str(dt_dev_pixelpipe_type_t pipe_type)
87{
88 switch(pipe_type)
89 {
91 return "PREVIEW";
93 return "FULL";
95 return "THUMBNAIL";
97 return "EXPORT";
98 default:
99 return "UNKNOWN";
100 }
101}
102
107 0.0f,
108 100.0f,
110 0,
111 0,
112 0.0f,
114 0.0f,
115 0.0f,
116 0.0f,
117 0.0f, // detail mask threshold
118 { 0, 0, 0 },
119 { 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,
120 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,
121 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,
122 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 },
123 { 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 },
124 { 0 }, 0, 0, FALSE };
125
127 gboolean is_scene_referred)
128{
129 if(module->flags() & IOP_FLAGS_SUPPORTS_BLENDING)
130 {
131 switch(module->blend_colorspace(module, NULL, NULL))
132 {
133 case IOP_CS_RAW:
135 case IOP_CS_LAB:
136 case IOP_CS_LCH:
138 case IOP_CS_RGB:
140 return is_scene_referred ? DEVELOP_BLEND_CS_RGB_SCENE : DEVELOP_BLEND_CS_RGB_DISPLAY;
141 case IOP_CS_HSL:
143 case IOP_CS_JZCZHZ:
145 default:
147 }
148 }
149 else
151}
152
157
159{
161 switch(cst)
162 {
164 return module_cst == DEVELOP_BLEND_CS_RAW;
166 {
167 // Lab is reached through the working profile whatever the module's position, so it only means
168 // something where the pipe's own profile choice is the working one: never on camera RGB nor on
169 // the display encoding. An instance not placed in the pipe yet, parked at INT_MAX, is taken as
170 // sitting in the working space.
171 if(module_cst == DEVELOP_BLEND_CS_LAB) return TRUE;
172 if(module_cst != DEVELOP_BLEND_CS_RGB_SCENE) return FALSE;
173 if(module->iop_order == INT_MAX) return TRUE;
175 }
177 // converted through the profile of the module's own position -- input, working or output, see
178 // dt_develop_blendif_init_masking_profile() -- so it is valid wherever the module sits; RGB
179 // (display) reads the channels as they are
181 return module_cst == DEVELOP_BLEND_CS_LAB || module_cst == DEVELOP_BLEND_CS_RGB_SCENE
182 || module_cst == DEVELOP_BLEND_CS_RGB_DISPLAY;
183 default:
184 return FALSE;
185 }
186}
187
190{
192 {
193 // update the default boost parameters for Jz and Cz so that the sRGB white is represented by a value
194 // "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
195 // as 1.8. In order to allow enough sensitivity in the low values, the boost factor should be set to
196 // log2(0.001) = -6.64385619. To keep the minimum boost factor at zero an offset of that value is added in
197 // the GUI. To display the initial boost factor at zero, the default value will be set to that value also.
198 blend_params->blendif_boost_factors[DEVELOP_BLENDIF_Jz_in] = -6.64385619f;
199 blend_params->blendif_boost_factors[DEVELOP_BLENDIF_Cz_in] = -6.64385619f;
200 blend_params->blendif_boost_factors[DEVELOP_BLENDIF_Jz_out] = -6.64385619f;
201 blend_params->blendif_boost_factors[DEVELOP_BLENDIF_Cz_out] = -6.64385619f;
202 }
203}
204
211
214{
215 memcpy(blend_params, &_default_blendop_params, sizeof(dt_develop_blend_params_t));
216 blend_params->blend_cst = cst;
217 _blend_init_blendif_boost_parameters(blend_params, cst);
218}
219
233
236{
237 const dt_develop_blend_params_t *const bp = (const dt_develop_blend_params_t *)piece->blendop_data;
238 if(IS_NULL_PTR(bp)) return cst;
239 switch(bp->blend_cst)
240 {
242 return IOP_CS_RAW;
244 return IOP_CS_LAB;
247 return IOP_CS_RGB;
248 default:
249 return cst;
250 }
251}
252
253void dt_develop_blendif_process_parameters(float *const restrict parameters,
255{
256 const int32_t blend_csp = params->blend_cst;
257 const uint32_t blendif = params->blendif;
258 const float *blendif_parameters = params->blendif_parameters;
259 const float *boost_factors = params->blendif_boost_factors;
260 for(size_t i = 0, j = 0; i < DEVELOP_BLENDIF_SIZE; i++, j += DEVELOP_BLENDIF_PARAMETER_ITEMS)
261 {
262 if(blendif & (1 << i))
263 {
264 float offset = 0.0f;
267 {
268 offset = 0.5f;
269 }
270 parameters[j + 0] = (blendif_parameters[i * 4 + 0] - offset) * exp2f(boost_factors[i]);
271 parameters[j + 1] = (blendif_parameters[i * 4 + 1] - offset) * exp2f(boost_factors[i]);
272 parameters[j + 2] = (blendif_parameters[i * 4 + 2] - offset) * exp2f(boost_factors[i]);
273 parameters[j + 3] = (blendif_parameters[i * 4 + 3] - offset) * exp2f(boost_factors[i]);
274 // pre-compute increasing slope and decreasing slope
275 parameters[j + 4] = 1.0f / fmaxf(0.001f, parameters[j + 1] - parameters[j + 0]);
276 parameters[j + 5] = 1.0f / fmaxf(0.001f, parameters[j + 3] - parameters[j + 2]);
277 // handle the case when one end is open to avoid clipping input/output values
278 if(blendif_parameters[i * 4 + 0] <= 0.0f && blendif_parameters[i * 4 + 1] <= 0.0f)
279 {
280 parameters[j + 0] = -INFINITY;
281 parameters[j + 1] = -INFINITY;
282 }
283 if(blendif_parameters[i * 4 + 2] >= 1.0f && blendif_parameters[i * 4 + 3] >= 1.0f)
284 {
285 parameters[j + 2] = INFINITY;
286 parameters[j + 3] = INFINITY;
287 }
288 }
289 else
290 {
291 parameters[j + 0] = -INFINITY;
292 parameters[j + 1] = -INFINITY;
293 parameters[j + 2] = INFINITY;
294 parameters[j + 3] = INFINITY;
295 parameters[j + 4] = 0.0f;
296 parameters[j + 5] = 0.0f;
297 }
298 }
299}
300
303 gboolean *top_enabled,
304 gboolean *raster_used,
305 gboolean *drawn_used,
306 gboolean *parametric_used)
307{
308 if(!IS_NULL_PTR(top_enabled)) *top_enabled = FALSE;
309 if(!IS_NULL_PTR(raster_used)) *raster_used = FALSE;
310 if(!IS_NULL_PTR(drawn_used)) *drawn_used = FALSE;
311 if(!IS_NULL_PTR(parametric_used)) *parametric_used = FALSE;
312 if(IS_NULL_PTR(params)) return;
313
314 const uint32_t mask_mode = params->mask_mode;
315 const gboolean top = (mask_mode & DEVELOP_MASK_ENABLED) != 0;
316 const gboolean raster_mode = (mask_mode & DEVELOP_MASK_RASTER) != 0;
317 const gboolean drawn_mode = (mask_mode & DEVELOP_MASK_SHAPE) != 0;
318 const gboolean parametric_mode = (mask_mode & DEVELOP_MASK_PARAMETRIC) != 0;
319
320 gboolean raster = raster_mode
321 && (params->raster_mask_id > 0
322 || params->raster_mask_source[0] != '\0'
323 || (!IS_NULL_PTR(module) && !IS_NULL_PTR(module->raster_mask.sink.source)));
324
325 gboolean drawn = FALSE;
326 if(drawn_mode && !IS_NULL_PTR(module) && !IS_NULL_PTR(module->dev))
327 {
328 dt_masks_form_t *grp = dt_masks_get_from_id(module->dev, params->mask_id);
329 drawn = !IS_NULL_PTR(grp) && (grp->type & DT_MASKS_GROUP) && g_list_length(grp->points) > 0;
330 }
331
332 gboolean parametric = FALSE;
333 if(parametric_mode)
334 {
335 const float threshold_epsilon = 1e-6f;
336 const uint32_t channel_mask = params->blend_cst == DEVELOP_BLEND_CS_LAB
339 uint32_t active_channels = 0;
340 for(uint32_t ch = 0; ch < DEVELOP_BLENDIF_SIZE; ch++)
341 {
342 const uint32_t bit = 1u << ch;
343 if(!(channel_mask & bit) || !(params->blendif & bit)) continue;
344 const float *channel = &params->blendif_parameters[ch * 4];
345 if(fabsf(channel[0]) > threshold_epsilon
346 || fabsf(channel[1]) > threshold_epsilon
347 || fabsf(channel[2] - 1.0f) > threshold_epsilon
348 || fabsf(channel[3] - 1.0f) > threshold_epsilon)
349 active_channels |= bit;
350 }
351 parametric = active_channels != 0;
352 }
353
354 if(!IS_NULL_PTR(top_enabled)) *top_enabled = top;
355 if(!IS_NULL_PTR(raster_used)) *raster_used = raster;
356 if(!IS_NULL_PTR(drawn_used)) *drawn_used = drawn;
357 if(!IS_NULL_PTR(parametric_used)) *parametric_used = parametric;
358}
359
360// See function definition in blend.h for important information
362 const struct dt_dev_pixelpipe_iop_t *piece,
363 dt_iop_order_iccprofile_info_t *blending_profile,
365{
366 // Bradford adaptation matrix from http://www.brucelindbloom.com/index.html?Eqn_ChromAdapt.html
367 const dt_colormatrix_t M = {
368 { 0.9555766f, -0.0230393f, 0.0631636f, 0.0f },
369 { -0.0282895f, 1.0099416f, 0.0210077f, 0.0f },
370 { 0.0122982f, -0.0204830f, 1.3299098f, 0.0f },
371 };
372
373 const dt_iop_order_iccprofile_info_t *const profile = (cst == DEVELOP_BLEND_CS_RGB_SCENE)
376 if(IS_NULL_PTR(profile)) return 0;
377
378 memcpy(blending_profile, profile, sizeof(dt_iop_order_iccprofile_info_t));
379 for(size_t y = 0; y < 3; y++)
380 {
381 for(size_t x = 0; x < 3; x++)
382 {
383 float sum = 0.0f;
384 for(size_t i = 0; i < 3; i++)
385 sum += M[y][i] * profile->matrix_in[i][x];
386 blending_profile->matrix_out[y][x] = sum;
387 blending_profile->matrix_out_transposed[x][y] = sum;
388 }
389 }
390
391 return 1;
392}
393
394static inline float _detail_mask_threshold(const float level, const gboolean detail)
395{
396 // this does some range calculation for smoother ui experience
397 return 0.005f * (detail ? powf(level, 2.0f) : 1.0f - powf(fabs(level), 0.5f ));
398}
399
400static void _refine_with_detail_mask(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe,
401 const struct dt_dev_pixelpipe_iop_t *piece, float *mask,
402 const float level)
403{
404 const dt_iop_roi_t *const roi_out = &piece->roi_out;
405 if(level == 0.0f) return;
406 const gboolean info = ((dt_get_debug_flags() & DT_DEBUG_MASKS) && (pipe->type == DT_DEV_PIXELPIPE_FULL));
407
408 const gboolean detail = (level > 0.0f);
409 const float threshold = _detail_mask_threshold(level, detail);
410
411 float *tmp = NULL;
412 float *lum = NULL;
413 float *warp_mask = NULL;
414 float *rawdetail_mask = NULL;
415
416 const dt_dev_pixelpipe_t *p = pipe;
417 rawdetail_mask = dt_dev_retrieve_rawdetail_mask(pipe, self);
418 if(IS_NULL_PTR(rawdetail_mask)) return;
419
420 const int iwidth = p->rawdetail_mask_roi.width;
421 const int iheight = p->rawdetail_mask_roi.height;
422 const int owidth = roi_out->width;
423 const int oheight = roi_out->height;
424 if(info) fprintf(stderr, "[_refine_with_detail_mask] in module %s %ix%i --> %ix%i\n", self->op, iwidth, iheight, owidth, oheight);
425
426 const int bufsize = MAX(iwidth * iheight, owidth * oheight);
427
430 if((IS_NULL_PTR(tmp)) || (IS_NULL_PTR(lum))) goto error;
431
432 dt_masks_calc_detail_mask(rawdetail_mask, lum, tmp, iwidth, iheight, threshold, detail);
434 tmp = NULL;
435
436 // here we have the slightly blurred full detail mask available
437 warp_mask = dt_dev_distort_detail_mask(p, lum, self);
438 // dt_dev_distort_detail_mask() may return `lum` unchanged when no geometric distortion is needed.
439 const gboolean warp_mask_aliases_lum = (warp_mask == lum);
440 if(!warp_mask_aliases_lum)
441 {
443 lum = NULL;
444 }
445
446 if(IS_NULL_PTR(warp_mask)) goto error;
447
448 const int msize = owidth * oheight;
449 __OMP_PARALLEL_FOR_SIMD__(aligned(mask, warp_mask : 64))
450 for(int idx =0; idx < msize; idx++)
451 {
452 mask[idx] = mask[idx] * warp_mask[idx];
453 }
455 if(warp_mask_aliases_lum) lum = NULL;
456
457 return;
458
459 error:
463 gchar *item = g_strdup_printf(_("`%s` on %s"), self->op, pipe->dev->image_storage.fullpath);
464 dt_control_alert(_("Module failed"), _("detail mask blending error"), item);
465 dt_free(item);
466}
467
469 const dt_dev_pixelpipe_iop_t *const piece,
470 _develop_mask_post_processing operations[3])
471{
472 const gboolean mask_feather = params->feathering_radius > 0.1f && piece->dsc_in.channels >= 3;
473 const gboolean mask_blur = params->blur_radius > 0.1f;
474 const gboolean mask_tone_curve = fabsf(params->contrast) >= 0.01f || fabsf(params->brightness) >= 0.01f;
475 const gboolean mask_feather_before = params->feathering_guide == DEVELOP_MASK_GUIDE_IN_BEFORE_BLUR
476 || params->feathering_guide == DEVELOP_MASK_GUIDE_OUT_BEFORE_BLUR;
477 const gboolean mask_feather_out = params->feathering_guide == DEVELOP_MASK_GUIDE_OUT_BEFORE_BLUR
478 || params->feathering_guide == DEVELOP_MASK_GUIDE_OUT_AFTER_BLUR;
479 const float opacity = fminf(fmaxf(params->opacity / 100.0f, 0.0f), 1.0f);
480
481 memset(operations, 0, sizeof(_develop_mask_post_processing) * 3);
482 size_t index = 0;
483
484 if(mask_feather)
485 {
486 if(mask_blur && mask_feather_before)
487 {
488 operations[index++] = mask_feather_out ? DEVELOP_MASK_POST_FEATHER_OUT : DEVELOP_MASK_POST_FEATHER_IN;
489 operations[index++] = DEVELOP_MASK_POST_BLUR;
490 }
491 else
492 {
493 if(mask_blur)
494 operations[index++] = DEVELOP_MASK_POST_BLUR;
495 operations[index++] = mask_feather_out ? DEVELOP_MASK_POST_FEATHER_OUT : DEVELOP_MASK_POST_FEATHER_IN;
496 }
497 }
498 else if(mask_blur)
499 {
500 operations[index++] = DEVELOP_MASK_POST_BLUR;
501 }
502
503 if(mask_tone_curve && opacity > 1e-4f)
504 {
505 operations[index++] = DEVELOP_MASK_POST_TONE_CURVE;
506 }
507
508 return index;
509}
510
511
512static inline float *_develop_blend_process_copy_region(const float *const restrict input, const size_t iwidth,
513 const size_t xoffs, const size_t yoffs,
514 const size_t owidth, const size_t oheight)
515{
516 const size_t ioffset = yoffs * iwidth + xoffs;
517 float *const restrict output =
519 if(IS_NULL_PTR(output))
520 {
521 return NULL;
522 }
524 for(size_t y = 0; y < oheight; y++)
525 {
526 const size_t iindex = y * iwidth + ioffset;
527 const size_t oindex = y * owidth;
528 memcpy(output + oindex, input + iindex, sizeof(float) * owidth);
529 }
530
531 return output;
532}
533
534static inline void _develop_blend_process_free_region(float *const restrict input)
535{
537}
538
540 const dt_iop_module_t *const self)
541{
542 if(IS_NULL_PTR(params) || IS_NULL_PTR(self)) return NULL;
543
544 const dt_iop_module_t *source = self->raster_mask.sink.source;
545 if(source && !strcmp(source->op, params->raster_mask_source)
546 && source->multi_priority == params->raster_mask_instance)
547 return source;
548
549 if(IS_NULL_PTR(self->dev) || params->raster_mask_source[0] == '\0') return NULL;
550
551 for(GList *iter = g_list_first(self->dev->iop); iter; iter = g_list_next(iter))
552 {
553 const dt_iop_module_t *candidate = (const dt_iop_module_t *)iter->data;
554 if(!strcmp(candidate->op, params->raster_mask_source)
555 && candidate->multi_priority == params->raster_mask_instance)
556 return candidate;
557 }
558
559 return NULL;
560}
561
563 dt_iop_module_t *self,
566 float *const restrict mask,
567 const size_t owidth,
568 const size_t oheight,
569 int *const raster_error)
570{
571 int local_raster_error = 0;
573 float *raster_mask = raster_source
574 ? dt_dev_get_raster_mask(pipe, raster_source, params->raster_mask_id,
575 self, &local_raster_error)
576 : NULL;
577
578 if(!IS_NULL_PTR(raster_mask))
579 {
580 if(params->raster_mask_invert)
581 {
582 __OMP_FOR_SIMD__(aligned(mask, raster_mask:64) )
583 for(size_t i = 0; i < owidth * oheight; i++)
584 mask[i] = 1.0f - raster_mask[i];
585 }
586 else
587 {
588 dt_iop_image_scaled_copy(mask, raster_mask, 1.0f, owidth, oheight, 1);
589 }
590
592 }
593 else
594 {
595 const float value = params->raster_mask_invert ? 0.0f : 1.0f;
596 dt_iop_image_fill(mask, value, owidth, oheight, 1);
597 }
598
599 if(!IS_NULL_PTR(raster_error)) *raster_error = local_raster_error;
600}
601
603 dt_iop_module_t *self,
606 const struct dt_iop_roi_t *const roi_out,
607 float *const restrict mask,
608 const size_t owidth,
609 const size_t oheight)
610{
611 /* Resolve through the pipe's refcounted forms snapshot, never the live dev->forms: this runs
612 * on the worker while the GUI thread moves the very shape being rendered (see the retouch
613 * rule in CLAUDE.md). The live list is only a fallback for a pipe that took no snapshot. */
616 : dt_masks_get_from_id(self->dev, params->mask_id);
617
618 if(form && (!(self->flags() & IOP_FLAGS_NO_MASKS)) && (params->mask_mode & DEVELOP_MASK_SHAPE))
619 {
620 /* EMPTY is not a failure: the fold zeroes the buffer when no shape contributed, and a
621 * zero drawn mask is a legitimate state to blend with. Only ERROR leaves it undefined. */
622 if(dt_masks_group_render_roi(self, pipe, piece, form, roi_out, mask) == DT_MASKS_RASTER_ERROR)
623 return 1;
624
625 if(params->mask_combine & DEVELOP_COMBINE_MASKS_POS)
626 dt_iop_image_invert(mask, 1.0f, owidth, oheight, 1);
627 }
628 else if((!(self->flags() & IOP_FLAGS_NO_MASKS)) && (params->mask_mode & DEVELOP_MASK_SHAPE))
629 {
630 const float fill = (params->mask_combine & DEVELOP_COMBINE_MASKS_POS) ? 0.0f : 1.0f;
631 dt_iop_image_fill(mask, fill, owidth, oheight, 1);
632 }
633 else
634 {
635 const float fill = (params->mask_combine & DEVELOP_COMBINE_INCL) ? 0.0f : 1.0f;
636 dt_iop_image_fill(mask, fill, owidth, oheight, 1);
637 }
638
639 return 0;
640}
641
642static void _develop_blend_combine_masks(float *const restrict mask,
643 const float *const restrict other_mask,
644 const size_t buffsize)
645{
646 __OMP_FOR_SIMD__(aligned(mask, other_mask:64) )
647 for(size_t i = 0; i < buffsize; i++)
648 mask[i] *= other_mask[i];
649}
650
651
652static int _develop_blend_process_feather(const float *const guide, float *const mask, const size_t width,
653 const size_t height, const int ch, const float guide_weight,
654 const float feathering_radius, const float scale)
655{
656 const float sqrt_eps = 1.f;
657 int w = (int)(2 * feathering_radius * scale + 0.5f);
658 if(w < 1) w = 1;
659
660 float *const restrict mask_bak =
662 if(IS_NULL_PTR(mask_bak)) return 1;
663
664 memcpy(mask_bak, mask, sizeof(float) * width * height);
665 if(guided_filter(guide, mask_bak, mask, width, height, ch, w, sqrt_eps, guide_weight, 0.f, 1.f) != 0)
666 {
668 return 1;
669 }
671 return 0;
672}
673
674
675static void _develop_blend_process_mask_tone_curve(float *const restrict mask, const size_t buffsize,
676 const float contrast, const float brightness,
677 const float opacity)
678{
679 const float mask_epsilon = 16 * FLT_EPSILON; // empirical mask threshold for fully transparent masks
680 const float e = expf(3.f * contrast);
681 __OMP_PARALLEL_FOR_SIMD__(aligned(mask:64))
682 for(size_t k = 0; k < buffsize; k++)
683 {
684 float x = mask[k] / opacity;
685 x = 2.f * x - 1.f;
686 if (1.f - brightness <= 0.f)
687 x = mask[k] <= mask_epsilon ? -1.f : 1.f;
688 else if (1.f + brightness <= 0.f)
689 x = mask[k] >= 1.f - mask_epsilon ? 1.f : -1.f;
690 else if (brightness > 0.f)
691 {
692 x = (x + brightness) / (1.f - brightness);
693 x = fminf(x, 1.f);
694 }
695 else
696 {
697 x = (x + brightness) / (1.f + brightness);
698 x = fmaxf(x, -1.f);
699 }
700 mask[k] = clamp_range_f(
701 ((x * e / (1.f + (e - 1.f) * fabsf(x))) / 2.f + 0.5f) * opacity, 0.f, 1.f);
702 }
703}
704
705// Releases the raster mask line a lookup handed back without a buffer. A line created here and left
706// empty is flagged while held, so its release removes it.
707static void _develop_blend_release_mask_entry(dt_pixel_cache_entry_t *mask_entry, const int created)
708{
709 if(IS_NULL_PTR(mask_entry)) return;
710 if(created)
711 {
714 }
716}
717
718
720 const struct dt_dev_pixelpipe_iop_t *piece, const void *const ivoid,
721 void *const ovoid)
722{
723 const dt_iop_roi_t *const roi_in = &piece->roi_in;
724 const dt_iop_roi_t *const roi_out = &piece->roi_out;
725 if(pipe->bypass_blendif && self->dev->gui_attached && (self == self->dev->gui_module)) return 0;
726
727 const dt_develop_blend_params_t *const d = (const dt_develop_blend_params_t *const)piece->blendop_data;
728 if(IS_NULL_PTR(d)) return 0;
729
730 gboolean top_enabled = FALSE;
731 gboolean raster_used = FALSE;
732 gboolean drawn_used = FALSE;
733 gboolean parametric_used = FALSE;
734 dt_develop_blend_get_mask_usage(self, d, &top_enabled, &raster_used, &drawn_used, &parametric_used);
735 if(!top_enabled) return 0;
736 // A mask preview request must also be honored when every sub-mask is neutral.
737 // In that case no raster/drawn/parametric mask is "used", but the effective
738 // blend mask is still the uniform opacity mask written into alpha below.
739 const gboolean preview_mask_mode = top_enabled;
740
741 const size_t ch = piece->dsc_in.channels; // the number of channels in the buffer
742 const int xoffs = roi_out->x - roi_in->x;
743 const int yoffs = roi_out->y - roi_in->y;
744 const int iwidth = roi_in->width;
745 const int iheight = roi_in->height;
746 const int owidth = roi_out->width;
747 const int oheight = roi_out->height;
748 const size_t buffsize = (size_t)owidth * oheight;
749 const float iscale = roi_in->scale;
750 const float oscale = roi_out->scale;
751 const gboolean rois_equal = iwidth == owidth || iheight == oheight || xoffs == 0 || yoffs == 0;
752
753 // In most cases of blending-enabled modules input and output of the module have
754 // the exact same dimensions. Only in very special cases we allow a module's input
755 // to exceed its output. This is namely the case for the spot removal module where
756 // the source of a patch might lie outside the roi of the output image. Therefore:
757 // We can only handle blending if roi_out and roi_in have the same scale and
758 // if roi_out fits into the area given by roi_in. xoffs and yoffs describe the relative
759 // offset of the input image to the output image.
760 if(oscale != iscale || xoffs < 0 || yoffs < 0
761 || ((xoffs > 0 || yoffs > 0) && (owidth + xoffs > iwidth || oheight + yoffs > iheight)))
762 {
763 gchar *item = g_strdup_printf(_("`%s` on %s"), self->op, pipe->dev->image_storage.fullpath);
764 dt_control_alert(_("Module failed"), _("skipped blending: roi's do not match"), item);
765 dt_free(item);
766 return 0;
767 }
768
769 // does user want us to display a specific channel?
770 const dt_dev_pixelpipe_display_mask_t request_mask_display =
771 (self->dev->gui_attached && (self == self->dev->gui_module) && (pipe == self->dev->pipe)
772 && preview_mask_mode)
775
776 // get channel max values depending on colorspace
777 const dt_develop_blend_colorspace_t blend_csp = d->blend_cst;
779
780 // obtaining the list of mask operations to perform
781 _develop_mask_post_processing post_operations[3];
782 const size_t post_operations_size = _develop_mask_get_post_operations(d, piece, post_operations);
783
784 // get the clipped opacity value 0 - 1
785 const float opacity = fminf(fmaxf(d->opacity / 100.0f, 0.0f), 1.0f);
786
787 // allocate space for blend mask
788 float *const restrict _mask = dt_pixelpipe_cache_alloc_align_float(buffsize, pipe);
789 if(IS_NULL_PTR(_mask))
790 {
791 dt_control_alert(_("Not enough memory"), _("could not allocate buffer for blending"),
793 return 1;
794 }
795 int raster_error = 0;
796 float *const restrict mask = _mask;
797 const gboolean use_masks = raster_used || drawn_used || parametric_used;
798 const gboolean raster_only = raster_used && !drawn_used && !parametric_used;
799
800 if(!use_masks)
801 {
802 // blend uniformly (no drawn or parametric mask)
803 dt_iop_image_fill(mask,opacity,owidth,oheight,1); //mask[k] = opacity;
804 }
805 else if(raster_only)
806 {
807 /* use a raster mask from another module earlier in the pipe */
808 _develop_blend_init_raster_mask(d, self, pipe, piece, mask, owidth, oheight, &raster_error);
809 dt_iop_image_mul_const(mask, opacity, owidth, oheight, 1);
810 }
811 else
812 {
813 if(!raster_used && !drawn_used)
814 {
815 // Parametric-only blending has no raster/drawn form mask to seed `mask`.
816 // The combination code below loops on parametric channels and composes them
817 // with that form mask, so initialize it as the neutral value of the chosen
818 // mask-combine operator.
819 const float fill = (d->mask_combine & DEVELOP_COMBINE_INCL) ? 0.0f : 1.0f;
820 dt_iop_image_fill(mask, fill, owidth, oheight, 1);
821 }
822 else if(raster_used)
823 {
824 _develop_blend_init_raster_mask(d, self, pipe, piece, mask, owidth, oheight, &raster_error);
825
826 if(drawn_used)
827 {
828 float *const restrict drawn_mask = dt_pixelpipe_cache_alloc_align_float(buffsize, pipe);
829 if(IS_NULL_PTR(drawn_mask))
830 {
831 dt_control_alert(_("Not enough memory"), _("could not allocate buffer for blending"),
834 return 1;
835 }
836
837 if(_develop_blend_init_drawn_mask(d, self, pipe, piece, roi_out, drawn_mask, owidth, oheight) != 0)
838 {
841 return 1;
842 }
843
844 _develop_blend_combine_masks(mask, drawn_mask, buffsize);
846 }
847 }
848 else if(drawn_used
849 && _develop_blend_init_drawn_mask(d, self, pipe, piece, roi_out, mask, owidth, oheight) != 0)
850 {
852 return 1;
853 }
854
855 _refine_with_detail_mask(self, pipe, piece, mask, d->details);
856
857 // get parametric mask (if any) and apply global opacity
858 switch(blend_csp)
859 {
861 dt_develop_blendif_lab_make_mask(piece, (const float *const restrict)ivoid,
862 (const float *const restrict)ovoid, mask);
863 break;
865 dt_develop_blendif_rgb_hsl_make_mask(pipe, piece, (const float *const restrict)ivoid,
866 (const float *const restrict)ovoid, mask);
867 break;
869 dt_develop_blendif_rgb_jzczhz_make_mask(pipe, piece, (const float *const restrict)ivoid,
870 (const float *const restrict)ovoid, mask);
871 break;
873 dt_develop_blendif_raw_make_mask(piece, (const float *const restrict)ivoid,
874 (const float *const restrict)ovoid, mask);
875 break;
876 default:
877 break;
878 }
879
880 // post processing the mask
881 for(size_t index = 0; index < post_operations_size; ++index)
882 {
883 _develop_mask_post_processing operation = post_operations[index];
884 if(operation == DEVELOP_MASK_POST_FEATHER_IN)
885 {
886 const float guide_weight = dt_iop_colorspace_is_rgb(cst) ? 100.0f : 1.0f;
887 float *restrict guide = (float *restrict)ivoid;
888 if(!rois_equal)
889 guide = _develop_blend_process_copy_region(guide, ch * iwidth, ch * xoffs, ch * yoffs,
890 ch * owidth, ch * oheight);
891 if(!guide)
892 {
894 return 1;
895 }
896 if(_develop_blend_process_feather(guide, mask, owidth, oheight, ch, guide_weight,
897 d->feathering_radius, roi_out->scale) != 0)
898 {
899 if(!rois_equal)
902 return 1;
903 }
904 if(!rois_equal)
906 }
907 else if(operation == DEVELOP_MASK_POST_FEATHER_OUT)
908 {
909 const float guide_weight = dt_iop_colorspace_is_rgb(cst) ? 100.0f : 1.0f;
910 if(_develop_blend_process_feather((const float *const restrict)ovoid, mask, owidth, oheight, ch,
911 guide_weight, d->feathering_radius, roi_out->scale) != 0)
912 {
914 return 1;
915 }
916 }
917 else if(operation == DEVELOP_MASK_POST_BLUR)
918 {
919 const float sigma = d->blur_radius * roi_out->scale;
920 const float mmax[] = { 1.0f };
921 const float mmin[] = { 0.0f };
922
923 dt_gaussian_t *g = dt_gaussian_init(owidth, oheight, 1, mmax, mmin, sigma, 0);
924 if(g)
925 {
926 dt_gaussian_blur(g, mask, mask);
928 }
929 }
930 else if(operation == DEVELOP_MASK_POST_TONE_CURVE)
931 {
932 _develop_blend_process_mask_tone_curve(mask, buffsize, d->contrast, d->brightness, opacity);
933 }
934 }
935 }
936
937 // now apply blending with per-pixel opacity value as defined in mask
938 // select the blend operator
939 switch(blend_csp)
940 {
942 dt_develop_blendif_lab_blend(pipe, piece, (const float *const restrict)ivoid, (float *const restrict)ovoid,
943 mask, request_mask_display);
944 break;
946 dt_develop_blendif_rgb_hsl_blend(pipe, piece, (const float *const restrict)ivoid, (float *const restrict)ovoid,
947 mask, request_mask_display);
948 break;
950 dt_develop_blendif_rgb_jzczhz_blend(pipe, piece, (const float *const restrict)ivoid, (float *const restrict)ovoid,
951 mask, request_mask_display);
952 break;
954 dt_develop_blendif_raw_blend(pipe, piece, (const float *const restrict)ivoid, (float *const restrict)ovoid,
955 mask, request_mask_display);
956 break;
957 default:
958 break;
959 }
960
961 // register if _this_ module should expose mask or display channel
963 {
964 pipe->mask_display = request_mask_display;
965 }
966
967 // check if we should store the mask for export or use in subsequent modules
969 {
971 dt_pixel_cache_entry_t *mask_entry = NULL;
972 void *cache_data = NULL;
973 const int created = dt_dev_pixelpipe_cache_get(
974 mask_hash, sizeof(float) * buffsize,
975 "raster mask", pipe->type, TRUE, &cache_data, &mask_entry);
976
977 if(IS_NULL_PTR(cache_data) || IS_NULL_PTR(mask_entry))
978 {
979 _develop_blend_release_mask_entry(mask_entry, created);
981 return 1;
982 }
983
984 // Cache entries are immutable for a given provider state. Only the thread
985 // which created this dedicated key writes the mask; exact hits reuse it.
986 if(created)
987 {
988 memcpy(cache_data, _mask, sizeof(float) * buffsize);
990 }
991 // Transfer cache_get()'s reference to the pipe. It keeps this side-band
992 // output alive until the next graph state is prepared or the pipe closes.
993 g_array_append_val(pipe->raster_mask_hashes, mask_hash);
995
996 if(created && dt_supervisor_active())
999 piece->module->multi_priority),
1000 piece->hash, piece->global_hash, piece->module->op,
1001 piece->module->multi_priority, piece->module->iop_order,
1002 pipe->type, pipe->imgid, piece->roi_out.width,
1003 piece->roi_out.height, -1, sizeof(float) * buffsize,
1004 "raster mask");
1005
1007 "[raster masks] %s mask id 0 for module %s (%s) for pipe %s"
1008 " with cache hash %" PRIu64 "\n",
1009 created ? "published" : "reused cached",
1010 piece->module->op, piece->module->multi_name,
1011 dt_pipe_type_to_str(pipe->type), mask_hash);
1012 }
1013 else
1014 {
1016 "[raster masks] discarding unpublished mask id 0 for module %s (%s) for pipe %s\n",
1017 piece->module->op, piece->module->multi_name,
1020 }
1021 // raster error is the only one we catch
1022 return raster_error;
1023}
1024
1025#ifdef HAVE_OPENCL
1027 const struct dt_dev_pixelpipe_iop_t *piece, float *mask,
1028 const float level, const int devid)
1029{
1030 const dt_iop_roi_t *const roi_out = &piece->roi_out;
1031 if(level == 0.0f) return;
1032 const gboolean info = (dt_get_debug_flags() & DT_DEBUG_MASKS);
1033
1034 const int detail = (level > 0.0f);
1035 const float threshold = _detail_mask_threshold(level, detail);
1036 float *lum = NULL;
1037 float *rawdetail_mask = NULL;
1038 cl_mem tmp = NULL;
1039 cl_mem blur = NULL;
1040 cl_mem out = NULL;
1041
1042 const dt_dev_pixelpipe_t *p = pipe;
1043 rawdetail_mask = dt_dev_retrieve_rawdetail_mask(pipe, self);
1044 if(IS_NULL_PTR(rawdetail_mask)) return;
1045
1046 const int iwidth = p->rawdetail_mask_roi.width;
1047 const int iheight = p->rawdetail_mask_roi.height;
1048 const int owidth = roi_out->width;
1049 const int oheight = roi_out->height;
1050 if(info) fprintf(stderr, "[_refine_with_detail_mask_cl] in module %s %ix%i --> %ix%i\n", self->op, iwidth, iheight, owidth, oheight);
1051
1052 lum = dt_pixelpipe_cache_alloc_align_float((size_t)iwidth * iheight, pipe);
1053 if(IS_NULL_PTR(lum)) goto error;
1054 tmp = dt_opencl_alloc_device(devid, iwidth, iheight, sizeof(float));
1055 if(IS_NULL_PTR(tmp)) goto error;
1056 out = dt_opencl_alloc_device_buffer(devid, sizeof(float) * iwidth * iheight);
1057 if(IS_NULL_PTR(out)) goto error;
1058 blur = dt_opencl_alloc_device_buffer(devid, sizeof(float) * iwidth * iheight);
1059 if(IS_NULL_PTR(blur)) goto error;
1060
1061 {
1062 const int err = dt_opencl_write_host_to_device(devid, rawdetail_mask, tmp, iwidth, iheight, sizeof(float));
1063 if(err != CL_SUCCESS) goto error;
1064 }
1065
1066 {
1067 size_t sizes[3] = { ROUNDUPDWD(iwidth, devid), ROUNDUPDHT(iheight, devid), 1 };
1069 dt_opencl_set_kernel_arg(devid, kernel, 0, sizeof(cl_mem), &out);
1070 dt_opencl_set_kernel_arg(devid, kernel, 1, sizeof(cl_mem), &tmp);
1071 dt_opencl_set_kernel_arg(devid, kernel, 2, sizeof(int), &iwidth);
1072 dt_opencl_set_kernel_arg(devid, kernel, 3, sizeof(int), &iheight);
1073 const int err = dt_opencl_enqueue_kernel_2d(devid, kernel, sizes);
1074 if(err != CL_SUCCESS) goto error;
1075 }
1076
1077 {
1078 size_t sizes[3] = { ROUNDUPDWD(iwidth, devid), ROUNDUPDHT(iheight, devid), 1 };
1080 dt_opencl_set_kernel_arg(devid, kernel, 0, sizeof(cl_mem), &out);
1081 dt_opencl_set_kernel_arg(devid, kernel, 1, sizeof(cl_mem), &blur);
1082 dt_opencl_set_kernel_arg(devid, kernel, 2, sizeof(int), &iwidth);
1083 dt_opencl_set_kernel_arg(devid, kernel, 3, sizeof(int), &iheight);
1084 dt_opencl_set_kernel_arg(devid, kernel, 4, sizeof(float), &threshold);
1085 dt_opencl_set_kernel_arg(devid, kernel, 5, sizeof(int), &detail);
1086 const int err = dt_opencl_enqueue_kernel_2d(devid, kernel, sizes);
1087 if(err != CL_SUCCESS) goto error;
1088 }
1089
1090 {
1091 float blurmat[13];
1092 dt_masks_blur_9x9_coeff(blurmat, 2.0f);
1093 cl_mem dev_blurmat = NULL;
1094 dev_blurmat = dt_opencl_copy_host_to_device_constant(devid, sizeof(float) * 13, blurmat);
1095 if(!IS_NULL_PTR(dev_blurmat))
1096 {
1097 size_t sizes[3] = { ROUNDUPDWD(iwidth, devid), ROUNDUPDHT(iheight, devid), 1 };
1098 const int clkernel = _blendop_cl_global->kernel_mask_blur;
1099 dt_opencl_set_kernel_arg(devid, clkernel, 0, sizeof(cl_mem), &blur);
1100 dt_opencl_set_kernel_arg(devid, clkernel, 1, sizeof(cl_mem), &out);
1101 dt_opencl_set_kernel_arg(devid, clkernel, 2, sizeof(int), &iwidth);
1102 dt_opencl_set_kernel_arg(devid, clkernel, 3, sizeof(int), &iheight);
1103 dt_opencl_set_kernel_arg(devid, clkernel, 4, sizeof(cl_mem), (void *) &dev_blurmat);
1104 const int err = dt_opencl_enqueue_kernel_2d(devid, clkernel, sizes);
1105 dt_opencl_release_mem_object(dev_blurmat);
1106 if(err != CL_SUCCESS) goto error;
1107 }
1108 else
1109 {
1110 dt_opencl_release_mem_object(dev_blurmat);
1111 goto error;
1112 }
1113 }
1114
1115 {
1116 size_t sizes[3] = { ROUNDUPDWD(iwidth, devid), ROUNDUPDHT(iheight, devid), 1 };
1118 dt_opencl_set_kernel_arg(devid, kernel, 0, sizeof(cl_mem), &out);
1119 dt_opencl_set_kernel_arg(devid, kernel, 1, sizeof(cl_mem), &tmp);
1120 dt_opencl_set_kernel_arg(devid, kernel, 2, sizeof(int), &iwidth);
1121 dt_opencl_set_kernel_arg(devid, kernel, 3, sizeof(int), &iheight);
1122 const int err = dt_opencl_enqueue_kernel_2d(devid, kernel, sizes);
1123 if(err != CL_SUCCESS) goto error;
1124 }
1125
1126 {
1127 const int err = dt_opencl_read_host_from_device(devid, lum, tmp, iwidth, iheight, sizeof(float));
1128 if(err != CL_SUCCESS) goto error;
1129 }
1130
1134 tmp = blur = out = NULL;
1135
1136 // here we have the slightly blurred full detail available
1137 float *warp_mask = dt_dev_distort_detail_mask(p, lum, self);
1138 if(IS_NULL_PTR(warp_mask)) goto error;
1139 // dt_dev_distort_detail_mask() may return `lum` unchanged when no geometric distortion is needed.
1140 const gboolean warp_mask_aliases_lum = (warp_mask == lum);
1141 if(!warp_mask_aliases_lum)
1142 {
1144 lum = NULL;
1145 }
1146
1147 const int msize = owidth * oheight;
1148 __OMP_PARALLEL_FOR_SIMD__(aligned(mask, warp_mask : 64))
1149 for(int idx = 0; idx < msize; idx++)
1150 {
1151 mask[idx] = mask[idx] * warp_mask[idx];
1152 }
1154 if(warp_mask_aliases_lum) lum = NULL;
1155 return;
1156
1157 error:
1162 gchar *item = g_strdup_printf(_("`%s` on %s"), self->op, pipe->dev->image_storage.fullpath);
1163 dt_control_alert(_("Module failed"), _("detail mask CL blending problem"), item);
1164 dt_free(item);
1165}
1166
1167static inline void _blend_process_cl_exchange(cl_mem *a, cl_mem *b)
1168{
1169 cl_mem tmp = *a;
1170 *a = *b;
1171 *b = tmp;
1172}
1173
1175 const struct dt_dev_pixelpipe_iop_t *piece, cl_mem dev_in, cl_mem dev_out)
1176{
1177 const dt_iop_roi_t *const roi_in = &piece->roi_in;
1178 const dt_iop_roi_t *const roi_out = &piece->roi_out;
1179 if(pipe->bypass_blendif && self->dev->gui_attached && (self == self->dev->gui_module)) return 0;
1180
1181 dt_develop_blend_params_t *const d = (dt_develop_blend_params_t *const)piece->blendop_data;
1182 if(IS_NULL_PTR(d)) return 0;
1183
1184 gboolean top_enabled = FALSE;
1185 gboolean raster_used = FALSE;
1186 gboolean drawn_used = FALSE;
1187 gboolean parametric_used = FALSE;
1188 dt_develop_blend_get_mask_usage(self, d, &top_enabled, &raster_used, &drawn_used, &parametric_used);
1189 if(!top_enabled) return 0;
1190 const unsigned int mask_mode = d->mask_mode;
1191 // A mask preview request must also be honored when every sub-mask is neutral.
1192 // In that case no raster/drawn/parametric mask is "used", but the effective
1193 // blend mask is still the uniform opacity mask written into alpha below.
1194 const gboolean preview_mask_mode = top_enabled;
1195
1196 const int ch = piece->dsc_in.channels; // the number of channels in the buffer
1197 const int xoffs = roi_out->x - roi_in->x;
1198 const int yoffs = roi_out->y - roi_in->y;
1199 const int iwidth = roi_in->width;
1200 const int iheight = roi_in->height;
1201 const int owidth = roi_out->width;
1202 const int oheight = roi_out->height;
1203 const size_t buffsize = (size_t)owidth * oheight;
1204 const float iscale = roi_in->scale;
1205 const float oscale = roi_out->scale;
1206 const gboolean rois_equal = iwidth == owidth || iheight == oheight || xoffs == 0 || yoffs == 0;
1207
1208 // In most cases of blending-enabled modules input and output of the module have
1209 // the exact same dimensions. Only in very special cases we allow a module's input
1210 // to exceed its output. This is namely the case for the spot removal module where
1211 // the source of a patch might lie outside the roi of the output image. Therefore:
1212 // We can only handle blending if roi_out and roi_in have the same scale and
1213 // if roi_out fits into the area given by roi_in. xoffs and yoffs describe the relative
1214 // offset of the input image to the output image. */
1215 if(oscale != iscale || xoffs < 0 || yoffs < 0
1216 || ((xoffs > 0 || yoffs > 0) && (owidth + xoffs > iwidth || oheight + yoffs > iheight)))
1217 {
1218 gchar *item = g_strdup_printf(_("`%s` on %s"), self->op, pipe->dev->image_storage.fullpath);
1219 dt_control_alert(_("Module failed"), _("skipped blending: roi's do not match"), item);
1220 dt_free(item);
1221 return 0;
1222 }
1223
1224 // only non-zero if mask_display was set by an _earlier_ module
1226
1227 // does user want us to display a specific channel?
1228 const dt_dev_pixelpipe_display_mask_t request_mask_display
1229 = (self->dev->gui_attached && (self == self->dev->gui_module) && (pipe == self->dev->pipe)
1230 && preview_mask_mode)
1231 ? self->request_mask_display
1233
1234 // get channel max values depending on colorspace
1235 const dt_develop_blend_colorspace_t blend_csp = d->blend_cst;
1237
1238 // obtaining the list of mask operations to perform
1239 _develop_mask_post_processing post_operations[3];
1240 const size_t post_operations_size = _develop_mask_get_post_operations(d, piece, post_operations);
1241
1242 // get the clipped opacity value 0 - 1
1243 const float opacity = fminf(fmaxf(d->opacity / 100.0f, 0.0f), 1.0f);
1244 const gboolean use_masks = raster_used || drawn_used || parametric_used;
1245 const gboolean raster_only = raster_used && !drawn_used && !parametric_used;
1246
1247 // allocate space for blend mask
1248 float *_mask = dt_pixelpipe_cache_alloc_align_float(buffsize, pipe);
1249 if(IS_NULL_PTR(_mask))
1250 {
1251 dt_control_alert(_("Not enough memory"), _("could not allocate buffer for blending"),
1253 return 1;
1254 }
1255 float *const mask = _mask;
1256
1257 // setup some kernels
1258 int kernel_mask;
1259 int kernel;
1260 switch(blend_csp)
1261 {
1265 break;
1266
1270 break;
1271
1275 break;
1276
1278 default:
1281 break;
1282 }
1283 int kernel_mask_tone_curve = _blendop_cl_global->kernel_blendop_mask_tone_curve;
1284 int kernel_set_mask = _blendop_cl_global->kernel_blendop_set_mask;
1285 int kernel_display_channel = _blendop_cl_global->kernel_blendop_display_channel;
1286
1287 const int devid = pipe->devid;
1288 const int offs[2] = { xoffs, yoffs };
1289 const size_t sizes[] = { ROUNDUPDWD(owidth, devid), ROUNDUPDHT(oheight, devid), 1 };
1290
1291 cl_int err = -999;
1292 cl_mem dev_blendif_params = NULL;
1293 cl_mem dev_boost_factors = NULL;
1294 cl_mem dev_mask_1 = NULL;
1295 cl_mem dev_mask_2 = NULL;
1296 cl_mem dev_tmp = NULL;
1297 cl_mem dev_guide = NULL;
1298
1299 cl_mem dev_profile_info = NULL;
1300 cl_mem dev_profile_lut = NULL;
1301 dt_colorspaces_iccprofile_info_cl_t *profile_info_cl = NULL;
1302 cl_float *profile_lut_cl = NULL;
1303
1304 cl_mem dev_work_profile_info = NULL;
1305 cl_mem dev_work_profile_lut = NULL;
1306 dt_colorspaces_iccprofile_info_cl_t *work_profile_info_cl = NULL;
1307 cl_float *work_profile_lut_cl = NULL;
1308
1309 size_t origin[] = { 0, 0, 0 };
1310 size_t region[] = { owidth, oheight, 1 };
1311
1312 // parameters, for every channel the 4 limits + pre-computed increasing slope and decreasing slope
1315
1316
1317 // copy blend parameters to constant device memory
1318 dev_blendif_params = dt_opencl_copy_host_to_device_constant(devid, sizeof(parameters), parameters);
1319 if(IS_NULL_PTR(dev_blendif_params)) goto error;
1320
1321 dev_mask_1 = dt_opencl_alloc_device(devid, owidth, oheight, sizeof(float));
1322 if(IS_NULL_PTR(dev_mask_1)) goto error;
1323
1325 const int use_profile = dt_develop_blendif_init_masking_profile(pipe, piece, &profile, blend_csp);
1326
1327 err = dt_ioppr_build_iccprofile_params_cl(use_profile ? &profile : NULL, devid, &profile_info_cl,
1328 &profile_lut_cl, &dev_profile_info, &dev_profile_lut);
1329 if(err != CL_SUCCESS) goto error;
1330
1331 if(!use_masks)
1332 {
1333 // blend uniformly (no drawn or parametric mask)
1334
1335 // set dev_mask with global opacity value
1336 dt_opencl_set_kernel_arg(devid, kernel_set_mask, 0, sizeof(cl_mem), (void *)&dev_mask_1);
1337 dt_opencl_set_kernel_arg(devid, kernel_set_mask, 1, sizeof(int), (void *)&owidth);
1338 dt_opencl_set_kernel_arg(devid, kernel_set_mask, 2, sizeof(int), (void *)&oheight);
1339 dt_opencl_set_kernel_arg(devid, kernel_set_mask, 3, sizeof(float), (void *)&opacity);
1340 err = dt_opencl_enqueue_kernel_2d(devid, kernel_set_mask, sizes);
1341 if(err != CL_SUCCESS) goto error;
1342 }
1343 else if(raster_only)
1344 {
1345 int raster_error = 0;
1346 _develop_blend_init_raster_mask(d, self, pipe, piece, mask, owidth, oheight, &raster_error);
1347 if(raster_error) goto error;
1348 dt_iop_image_mul_const(mask, opacity, owidth, oheight, 1);
1349
1350 err = dt_opencl_write_host_to_device(devid, mask, dev_mask_1, owidth, oheight, sizeof(float));
1351 if(err != CL_SUCCESS) goto error;
1352 }
1353 else
1354 {
1355 if(!raster_used && !drawn_used)
1356 {
1357 // Parametric-only blending has no raster/drawn form mask to seed `mask`.
1358 // The OpenCL mask kernel reads that form mask from `dev_mask_1`, so keep
1359 // the CPU staging buffer explicit and initialized before upload.
1360 const float fill = (d->mask_combine & DEVELOP_COMBINE_INCL) ? 0.0f : 1.0f;
1361 dt_iop_image_fill(mask, fill, owidth, oheight, 1);
1362 }
1363 else if(raster_used)
1364 {
1365 int raster_error = 0;
1366 _develop_blend_init_raster_mask(d, self, pipe, piece, mask, owidth, oheight, &raster_error);
1367 if(raster_error) goto error;
1368
1369 if(drawn_used)
1370 {
1371 float *const restrict drawn_mask = dt_pixelpipe_cache_alloc_align_float(buffsize, pipe);
1372 if(IS_NULL_PTR(drawn_mask)) goto error;
1373
1374 if(_develop_blend_init_drawn_mask(d, self, pipe, piece, roi_out, drawn_mask, owidth, oheight) != 0)
1375 {
1377 goto error;
1378 }
1379
1380 _develop_blend_combine_masks(mask, drawn_mask, buffsize);
1382 }
1383 }
1384 else if(drawn_used
1385 && _develop_blend_init_drawn_mask(d, self, pipe, piece, roi_out, mask, owidth, oheight) != 0)
1386 {
1387 goto error;
1388 }
1389 _refine_with_detail_mask_cl(self, pipe, piece, mask, d->details, devid);
1390
1391 // write mask from host to device
1392 dev_mask_2 = dt_opencl_alloc_device(devid, owidth, oheight, sizeof(float));
1393 if(IS_NULL_PTR(dev_mask_2)) goto error;
1394 err = dt_opencl_write_host_to_device(devid, mask, dev_mask_1, owidth, oheight, sizeof(float));
1395 if(err != CL_SUCCESS) goto error;
1396
1397 // get parametric mask (if any) and apply global opacity
1398 const unsigned blendif = d->blendif;
1399 const unsigned int mask_combine = d->mask_combine;
1400 dt_opencl_set_kernel_arg(devid, kernel_mask, 0, sizeof(cl_mem), (void *)&dev_in);
1401 dt_opencl_set_kernel_arg(devid, kernel_mask, 1, sizeof(cl_mem), (void *)&dev_out);
1402 dt_opencl_set_kernel_arg(devid, kernel_mask, 2, sizeof(cl_mem), (void *)&dev_mask_1);
1403 dt_opencl_set_kernel_arg(devid, kernel_mask, 3, sizeof(cl_mem), (void *)&dev_mask_2);
1404 dt_opencl_set_kernel_arg(devid, kernel_mask, 4, sizeof(int), (void *)&owidth);
1405 dt_opencl_set_kernel_arg(devid, kernel_mask, 5, sizeof(int), (void *)&oheight);
1406 dt_opencl_set_kernel_arg(devid, kernel_mask, 6, sizeof(float), (void *)&opacity);
1407 dt_opencl_set_kernel_arg(devid, kernel_mask, 7, sizeof(unsigned), (void *)&blendif);
1408 dt_opencl_set_kernel_arg(devid, kernel_mask, 8, sizeof(cl_mem), (void *)&dev_blendif_params);
1409 dt_opencl_set_kernel_arg(devid, kernel_mask, 9, sizeof(unsigned), (void *)&mask_mode);
1410 dt_opencl_set_kernel_arg(devid, kernel_mask, 10, sizeof(unsigned), (void *)&mask_combine);
1411 dt_opencl_set_kernel_arg(devid, kernel_mask, 11, 2 * sizeof(int), (void *)&offs);
1412 dt_opencl_set_kernel_arg(devid, kernel_mask, 12, sizeof(cl_mem), (void *)&dev_profile_info);
1413 dt_opencl_set_kernel_arg(devid, kernel_mask, 13, sizeof(cl_mem), (void *)&dev_profile_lut);
1414 dt_opencl_set_kernel_arg(devid, kernel_mask, 14, sizeof(int), (void *)&use_profile);
1415 err = dt_opencl_enqueue_kernel_2d(devid, kernel_mask, sizes);
1416 if(err != CL_SUCCESS)
1417 {
1418 fprintf(stderr, "[dt_develop_blend_process_cl] error %i enqueue kernel\n", err);
1419 goto error;
1420 }
1421
1422 // the mask is now located in dev_mask_2, put it in dev_mask_1
1423 _blend_process_cl_exchange(&dev_mask_1, &dev_mask_2);
1424
1425 // post processing the mask (it will always be stored in dev_mask_1)
1426 for(size_t index = 0; index < post_operations_size; ++index)
1427 {
1428 _develop_mask_post_processing operation = post_operations[index];
1429 if(operation == DEVELOP_MASK_POST_FEATHER_IN)
1430 {
1431 int w = (int)(2 * d->feathering_radius * roi_out->scale + 0.5f);
1432 if (w < 1) w = 1;
1433 const float sqrt_eps = 1.0f;
1434 const float guide_weight = dt_iop_colorspace_is_rgb(cst) ? 100.0f : 1.0f;
1435
1436 cl_mem guide = dev_in;
1437 if(!rois_equal)
1438 {
1439 dev_guide = dt_opencl_alloc_device(devid, owidth, oheight, sizeof(float) * ch);
1440 if(IS_NULL_PTR(dev_guide)) goto error;
1441 guide = dev_guide;
1442 size_t origin_1[] = { xoffs, yoffs, 0 };
1443 size_t origin_2[] = { 0, 0, 0 };
1444 err = dt_opencl_enqueue_copy_image(devid, dev_in, guide, origin_2, origin_1, region);
1445 if(err != CL_SUCCESS) goto error;
1446 }
1447 if(guided_filter_cl(devid, guide, dev_mask_1, dev_mask_2, owidth, oheight, ch, w, sqrt_eps, guide_weight,
1448 0.0f, 1.0f) != 0)
1449 goto error;
1450 if(!rois_equal)
1451 {
1453 dev_guide = NULL;
1454 }
1455 _blend_process_cl_exchange(&dev_mask_1, &dev_mask_2);
1456 }
1457 else if(operation == DEVELOP_MASK_POST_FEATHER_OUT)
1458 {
1459 int w = (int)(2 * d->feathering_radius * roi_out->scale + 0.5f);
1460 if (w < 1) w = 1;
1461 const float sqrt_eps = 1.0f;
1462 const float guide_weight = dt_iop_colorspace_is_rgb(cst) ? 100.0f : 1.0f;
1463
1464 if(guided_filter_cl(devid, dev_out, dev_mask_1, dev_mask_2, owidth, oheight, ch, w, sqrt_eps, guide_weight,
1465 0.0f, 1.0f) != 0)
1466 goto error;
1467 _blend_process_cl_exchange(&dev_mask_1, &dev_mask_2);
1468 }
1469 else if(operation == DEVELOP_MASK_POST_BLUR)
1470 {
1471 const float sigma = d->blur_radius * roi_out->scale;
1472 const float mmax[] = { 1.0f };
1473 const float mmin[] = { 0.0f };
1474
1475 dt_gaussian_cl_t *g = dt_gaussian_init_cl(devid, owidth, oheight, 1, mmax, mmin, sigma, 0);
1476 if(IS_NULL_PTR(g)) goto error;
1477 err = dt_gaussian_blur_cl(g, dev_mask_1, dev_mask_2);
1479 if(err != CL_SUCCESS) goto error;
1480 _blend_process_cl_exchange(&dev_mask_1, &dev_mask_2);
1481 }
1482 else if(operation == DEVELOP_MASK_POST_TONE_CURVE)
1483 {
1484 const float e = expf(3.f * d->contrast);
1485 const float brightness = d->brightness;
1486 dt_opencl_set_kernel_arg(devid, kernel_mask_tone_curve, 0, sizeof(cl_mem), (void *)&dev_mask_1);
1487 dt_opencl_set_kernel_arg(devid, kernel_mask_tone_curve, 1, sizeof(cl_mem), (void *)&dev_mask_2);
1488 dt_opencl_set_kernel_arg(devid, kernel_mask_tone_curve, 2, sizeof(int), (void *)&owidth);
1489 dt_opencl_set_kernel_arg(devid, kernel_mask_tone_curve, 3, sizeof(int), (void *)&oheight);
1490 dt_opencl_set_kernel_arg(devid, kernel_mask_tone_curve, 4, sizeof(float), (void *)&e);
1491 dt_opencl_set_kernel_arg(devid, kernel_mask_tone_curve, 5, sizeof(float), (void *)&brightness);
1492 dt_opencl_set_kernel_arg(devid, kernel_mask_tone_curve, 6, sizeof(float), (void *)&opacity);
1493 err = dt_opencl_enqueue_kernel_2d(devid, kernel_mask_tone_curve, sizes);
1494 if(err != CL_SUCCESS) goto error;
1495 _blend_process_cl_exchange(&dev_mask_1, &dev_mask_2);
1496 }
1497 }
1498
1499 // get rid of dev_mask_2
1500 dt_opencl_release_mem_object(dev_mask_2);
1501 dev_mask_2 = NULL;
1502 }
1503
1504 // get temporary buffer for output image to overcome readonly/writeonly limitation
1505 dev_tmp = dt_opencl_alloc_device(devid, owidth, oheight, sizeof(float) * ch);
1506 if(IS_NULL_PTR(dev_tmp)) goto error;
1507
1508 err = dt_opencl_enqueue_copy_image(devid, dev_out, dev_tmp, origin, origin, region);
1509 if(err != CL_SUCCESS) goto error;
1510
1511 if(request_mask_display & DT_DEV_PIXELPIPE_DISPLAY_ANY)
1512 {
1513 // load the boost factors in the device memory
1514 dev_boost_factors = dt_opencl_copy_host_to_device_constant(devid, sizeof(d->blendif_boost_factors),
1515 d->blendif_boost_factors);
1516 if(IS_NULL_PTR(dev_boost_factors)) goto error;
1517
1518 // the display channel of Lab blending is generated in RGB and should be transformed to Lab
1519 // the transformation in the pipeline is currently always using the work profile
1521 const int use_work_profile = !IS_NULL_PTR(work_profile);
1522
1523 err = dt_ioppr_build_iccprofile_params_cl(work_profile, devid, &work_profile_info_cl, &work_profile_lut_cl,
1524 &dev_work_profile_info, &dev_work_profile_lut);
1525 if(err != CL_SUCCESS) goto error;
1526
1527 // let us display a specific channel
1528 dt_opencl_set_kernel_arg(devid, kernel_display_channel, 0, sizeof(cl_mem), (void *)&dev_in);
1529 dt_opencl_set_kernel_arg(devid, kernel_display_channel, 1, sizeof(cl_mem), (void *)&dev_tmp);
1530 dt_opencl_set_kernel_arg(devid, kernel_display_channel, 2, sizeof(cl_mem), (void *)&dev_mask_1);
1531 dt_opencl_set_kernel_arg(devid, kernel_display_channel, 3, sizeof(cl_mem), (void *)&dev_out);
1532 dt_opencl_set_kernel_arg(devid, kernel_display_channel, 4, sizeof(int), (void *)&owidth);
1533 dt_opencl_set_kernel_arg(devid, kernel_display_channel, 5, sizeof(int), (void *)&oheight);
1534 dt_opencl_set_kernel_arg(devid, kernel_display_channel, 6, 2 * sizeof(int), (void *)&offs);
1535 dt_opencl_set_kernel_arg(devid, kernel_display_channel, 7, sizeof(int), (void *)&request_mask_display);
1536 dt_opencl_set_kernel_arg(devid, kernel_display_channel, 8, sizeof(cl_mem), (void*)&dev_boost_factors);
1537 dt_opencl_set_kernel_arg(devid, kernel_display_channel, 9, sizeof(cl_mem), (void *)&dev_profile_info);
1538 dt_opencl_set_kernel_arg(devid, kernel_display_channel, 10, sizeof(cl_mem), (void *)&dev_profile_lut);
1539 dt_opencl_set_kernel_arg(devid, kernel_display_channel, 11, sizeof(int), (void *)&use_profile);
1540 dt_opencl_set_kernel_arg(devid, kernel_display_channel, 12, sizeof(cl_mem), (void *)&dev_work_profile_info);
1541 dt_opencl_set_kernel_arg(devid, kernel_display_channel, 13, sizeof(cl_mem), (void *)&dev_work_profile_lut);
1542 dt_opencl_set_kernel_arg(devid, kernel_display_channel, 14, sizeof(int), (void *)&use_work_profile);
1543 err = dt_opencl_enqueue_kernel_2d(devid, kernel_display_channel, sizes);
1544 if(err != CL_SUCCESS)
1545 {
1546 fprintf(stderr, "[dt_develop_blend_process_cl] error %i enqueue kernel\n", err);
1547 goto error;
1548 }
1549 }
1550 else
1551 {
1552 // apply blending with per-pixel opacity value as defined in dev_mask_1
1553 const unsigned int blend_mode = d->blend_mode;
1554 const float blend_parameter = exp2f(d->blend_parameter);
1555 dt_opencl_set_kernel_arg(devid, kernel, 0, sizeof(cl_mem), (void *)&dev_in);
1556 dt_opencl_set_kernel_arg(devid, kernel, 1, sizeof(cl_mem), (void *)&dev_tmp);
1557 dt_opencl_set_kernel_arg(devid, kernel, 2, sizeof(cl_mem), (void *)&dev_mask_1);
1558 dt_opencl_set_kernel_arg(devid, kernel, 3, sizeof(cl_mem), (void *)&dev_out);
1559 dt_opencl_set_kernel_arg(devid, kernel, 4, sizeof(int), (void *)&owidth);
1560 dt_opencl_set_kernel_arg(devid, kernel, 5, sizeof(int), (void *)&oheight);
1561 dt_opencl_set_kernel_arg(devid, kernel, 6, sizeof(unsigned), (void *)&blend_mode);
1562 dt_opencl_set_kernel_arg(devid, kernel, 7, sizeof(float), (void *)&blend_parameter);
1563 dt_opencl_set_kernel_arg(devid, kernel, 8, 2 * sizeof(int), (void *)&offs);
1564 dt_opencl_set_kernel_arg(devid, kernel, 9, sizeof(int), (void *)&mask_display);
1565 err = dt_opencl_enqueue_kernel_2d(devid, kernel, sizes);
1566 if(err != CL_SUCCESS) goto error;
1567 }
1568
1569 // register if _this_ module should expose mask or display channel
1571 {
1572 pipe->mask_display = request_mask_display;
1573 }
1574
1575
1576 // check if we should store the mask for export or use in subsequent modules
1578 {
1579 // get back final mask from the device to store it for later use
1580 if(!raster_only)
1581 {
1582 err = dt_opencl_copy_device_to_host(devid, mask, dev_mask_1, owidth, oheight, sizeof(float));
1583 if(err != CL_SUCCESS) goto error;
1584 }
1585
1586 const uint64_t mask_hash = dt_dev_pixelpipe_raster_mask_hash(piece, 0);
1587 dt_pixel_cache_entry_t *mask_entry = NULL;
1588 void *cache_data = NULL;
1589 const int created = dt_dev_pixelpipe_cache_get(
1590 mask_hash, sizeof(float) * buffsize,
1591 "raster mask", pipe->type, TRUE, &cache_data, &mask_entry);
1592
1593 if(IS_NULL_PTR(cache_data) || IS_NULL_PTR(mask_entry))
1594 {
1595 _develop_blend_release_mask_entry(mask_entry, created);
1596 goto error;
1597 }
1598
1599 // The OpenCL mask has been materialized into `_mask` above. Publish that
1600 // host payload once so CPU and GPU consumers share the same cache entry.
1601 if(created)
1602 {
1603 memcpy(cache_data, _mask, sizeof(float) * buffsize);
1605 }
1606 // Transfer cache_get()'s reference to the pipe. It keeps this side-band
1607 // output alive until the next graph state is prepared or the pipe closes.
1608 g_array_append_val(pipe->raster_mask_hashes, mask_hash);
1610 _mask = NULL;
1611
1612 if(created && dt_supervisor_active())
1614 dt_supervisor_node_key(pipe->type, piece->module->op,
1615 piece->module->multi_priority),
1616 piece->hash, piece->global_hash, piece->module->op,
1617 piece->module->multi_priority, piece->module->iop_order,
1618 pipe->type, pipe->imgid, piece->roi_out.width,
1619 piece->roi_out.height, devid, sizeof(float) * buffsize,
1620 "raster mask");
1621
1623 "[raster masks] %s mask id 0 for module %s (%s) for pipe %s"
1624 " with cache hash %" PRIu64 "\n",
1625 created ? "published" : "reused cached",
1626 piece->module->op, piece->module->multi_name,
1627 dt_pipe_type_to_str(pipe->type), mask_hash);
1628 }
1629 else
1630 {
1632 "[raster masks] discarding unpublished mask id 0 for module %s (%s) for pipe %s\n",
1633 piece->module->op, piece->module->multi_name,
1636 }
1637
1638 dt_opencl_release_mem_object(dev_blendif_params);
1639 dt_opencl_release_mem_object(dev_boost_factors);
1640 dt_opencl_release_mem_object(dev_mask_1);
1642 dt_ioppr_free_iccprofile_params_cl(&profile_info_cl, &profile_lut_cl, &dev_profile_info, &dev_profile_lut);
1643 dt_ioppr_free_iccprofile_params_cl(&work_profile_info_cl, &work_profile_lut_cl, &dev_work_profile_info,
1644 &dev_work_profile_lut);
1645 return 0;
1646
1647error:
1649 dt_opencl_release_mem_object(dev_blendif_params);
1650 dt_opencl_release_mem_object(dev_boost_factors);
1651 dt_opencl_release_mem_object(dev_mask_1);
1652 dt_opencl_release_mem_object(dev_mask_2);
1655 if(profile_info_cl) dt_ioppr_free_iccprofile_params_cl(&profile_info_cl, &profile_lut_cl, &dev_profile_info, &dev_profile_lut);
1656 if(work_profile_info_cl) dt_ioppr_free_iccprofile_params_cl(&work_profile_info_cl, &work_profile_lut_cl, &dev_work_profile_info,
1657 &dev_work_profile_lut);
1658 dt_print(DT_DEBUG_OPENCL, "[opencl_blendop] couldn't enqueue kernel! %d\n", err);
1659 return 1;
1660}
1661#endif
1662
1665{
1666#ifdef HAVE_OPENCL
1668
1669 const int program = 3; // blendop.cl, from programs.conf
1670 b->kernel_blendop_mask_Lab = dt_opencl_create_kernel(program, "blendop_mask_Lab");
1671 b->kernel_blendop_mask_RAW = dt_opencl_create_kernel(program, "blendop_mask_RAW");
1672 b->kernel_blendop_mask_rgb_hsl = dt_opencl_create_kernel(program, "blendop_mask_rgb_hsl");
1673 b->kernel_blendop_mask_rgb_jzczhz = dt_opencl_create_kernel(program, "blendop_mask_rgb_jzczhz");
1674 b->kernel_blendop_Lab = dt_opencl_create_kernel(program, "blendop_Lab");
1675 b->kernel_blendop_RAW = dt_opencl_create_kernel(program, "blendop_RAW");
1676 b->kernel_blendop_rgb_hsl = dt_opencl_create_kernel(program, "blendop_rgb_hsl");
1677 b->kernel_blendop_rgb_jzczhz = dt_opencl_create_kernel(program, "blendop_rgb_jzczhz");
1678 b->kernel_blendop_mask_tone_curve = dt_opencl_create_kernel(program, "blendop_mask_tone_curve");
1679 b->kernel_blendop_set_mask = dt_opencl_create_kernel(program, "blendop_set_mask");
1680 b->kernel_blendop_display_channel = dt_opencl_create_kernel(program, "blendop_display_channel");
1681
1682 const int program_rcd = 31;
1683 b->kernel_calc_Y0_mask = dt_opencl_create_kernel(program_rcd, "calc_Y0_mask");
1684 b->kernel_calc_scharr_mask = dt_opencl_create_kernel(program_rcd, "calc_scharr_mask");
1685 b->kernel_write_mask = dt_opencl_create_kernel(program_rcd, "writeout_mask");
1686 b->kernel_read_mask = dt_opencl_create_kernel(program_rcd, "readin_mask");
1687 b->kernel_calc_blend = dt_opencl_create_kernel(program_rcd, "calc_detail_blend");
1688 b->kernel_mask_blur = dt_opencl_create_kernel(program_rcd, "fastblur_mask_9x9");
1689
1691#endif
1692}
1693
1696{
1697#ifdef HAVE_OPENCL
1699 _blendop_cl_global = NULL;
1700 if(IS_NULL_PTR(b)) return;
1701
1702 dt_opencl_free_kernel(b->kernel_blendop_mask_Lab);
1703 dt_opencl_free_kernel(b->kernel_blendop_mask_RAW);
1704 dt_opencl_free_kernel(b->kernel_blendop_mask_rgb_hsl);
1705 dt_opencl_free_kernel(b->kernel_blendop_mask_rgb_jzczhz);
1706 dt_opencl_free_kernel(b->kernel_blendop_Lab);
1707 dt_opencl_free_kernel(b->kernel_blendop_RAW);
1708 dt_opencl_free_kernel(b->kernel_blendop_rgb_hsl);
1709 dt_opencl_free_kernel(b->kernel_blendop_rgb_jzczhz);
1710 dt_opencl_free_kernel(b->kernel_blendop_mask_tone_curve);
1711 dt_opencl_free_kernel(b->kernel_blendop_set_mask);
1712 dt_opencl_free_kernel(b->kernel_blendop_display_channel);
1713 dt_opencl_free_kernel(b->kernel_calc_Y0_mask);
1714 dt_opencl_free_kernel(b->kernel_calc_scharr_mask);
1715 dt_opencl_free_kernel(b->kernel_write_mask);
1716 dt_opencl_free_kernel(b->kernel_read_mask);
1717 dt_opencl_free_kernel(b->kernel_calc_blend);
1718 dt_opencl_free_kernel(b->kernel_mask_blur);
1719 dt_free(b);
1720#endif
1721}
1722
1725{
1726 return DEVELOP_BLEND_VERSION;
1727}
1728
1732{
1733 tiling->factor = 3.5f; // in + out + (guide, tmp) + two quarter buffers for the mask
1734 tiling->maxbuf = 1.0f;
1735 tiling->overhead = 0;
1736 tiling->overlap = 0;
1737 tiling->xalign = 1;
1738 tiling->yalign = 1;
1739
1740 dt_develop_blend_params_t *const bldata = (dt_develop_blend_params_t *const)piece->blendop_data;
1741 if(!IS_NULL_PTR(bldata))
1742 {
1743 if(bldata->details != 0.0f)
1744 tiling->factor += 0.75f; // details mask requires 3 additional quarter buffers
1745 }
1746}
1747
1751gboolean dt_develop_blend_params_is_all_zero(const void *params, size_t length)
1752{
1753 const char *data = (const char *)params;
1754
1755 for(size_t k = 0; k < length; k++)
1756 if(data[k]) return FALSE;
1757
1758 return TRUE;
1759}
1760
1761static uint32_t _blend_legacy_blend_mode(uint32_t legacy_blend_mode)
1762{
1763 uint32_t blend_mode = legacy_blend_mode & DEVELOP_BLEND_MODE_MASK;
1764 gboolean blend_reverse = FALSE;
1765 switch(blend_mode) {
1767 blend_mode = DEVELOP_BLEND_BOUNDED;
1768 break;
1770 blend_mode = DEVELOP_BLEND_BOUNDED;
1771 blend_reverse = TRUE;
1772 break;
1775 blend_mode = DEVELOP_BLEND_NORMAL2;
1776 break;
1778 blend_mode = DEVELOP_BLEND_MULTIPLY;
1779 blend_reverse = TRUE;
1780 break;
1781 default:
1782 break;
1783 }
1784 return (blend_reverse ? DEVELOP_BLEND_REVERSE : 0) | blend_mode;
1785}
1786
1788int dt_develop_blend_legacy_params(dt_iop_module_t *module, const void *const old_params,
1789 const int old_version, void *new_params, const int new_version,
1790 const int length)
1791{
1792 // edits before version 10 default to a display referred workflow
1794
1795 dt_develop_blend_params_t default_display_blend_params;
1796 dt_develop_blend_init_blend_parameters(&default_display_blend_params, cst);
1797
1798 // first deal with all-zero parameter sets, regardless of version number.
1799 // these occurred in previous darktable versions when modules without blend support stored zero-initialized data
1800 // in history stack. that's no problem unless the module gets blend support later (e.g. module exposure).
1801 // remedy: we simply initialize with the current default blend params in this case.
1802 if(dt_develop_blend_params_is_all_zero(old_params, length))
1803 {
1805
1806 *n = default_display_blend_params;
1807 return 0;
1808 }
1809
1810 if(old_version == 1 && new_version == 11)
1811 {
1813 typedef struct dt_develop_blend_params1_t
1814 {
1815 uint32_t mode;
1816 float opacity;
1817 uint32_t mask_id;
1818 } dt_develop_blend_params1_t;
1819
1820 if(length != sizeof(dt_develop_blend_params1_t)) return 1;
1821
1822 dt_develop_blend_params1_t *o = (dt_develop_blend_params1_t *)old_params;
1824
1825 *n = default_display_blend_params; // start with a fresh copy of default parameters
1827 n->blend_mode = _blend_legacy_blend_mode(o->mode);
1828 n->opacity = o->opacity;
1829 n->mask_id = o->mask_id;
1830 return 0;
1831 }
1832
1833 if(old_version == 2 && new_version == 11)
1834 {
1836 typedef struct dt_develop_blend_params2_t
1837 {
1839 uint32_t mode;
1841 float opacity;
1843 uint32_t mask_id;
1845 uint32_t blendif;
1847 float blendif_parameters[4 * 8];
1848 } dt_develop_blend_params2_t;
1849
1850 if(length != sizeof(dt_develop_blend_params2_t)) return 1;
1851
1852 dt_develop_blend_params2_t *o = (dt_develop_blend_params2_t *)old_params;
1854
1855 *n = default_display_blend_params; // start with a fresh copy of default parameters
1857 n->mask_mode |= ((o->blendif & (1u << DEVELOP_BLENDIF_active)) && (n->mask_mode == DEVELOP_MASK_ENABLED))
1859 : 0;
1860 n->blend_mode = _blend_legacy_blend_mode(o->mode);
1861 n->opacity = o->opacity;
1862 n->mask_id = o->mask_id;
1863 n->blendif = o->blendif & 0xff; // only just in case: knock out all bits
1864 // which were undefined in version
1865 // 2; also switch off old "active" bit
1866 for(int i = 0; i < (4 * 8); i++) n->blendif_parameters[i] = o->blendif_parameters[i];
1867
1868 return 0;
1869 }
1870
1871 if(old_version == 3 && new_version == 11)
1872 {
1874 typedef struct dt_develop_blend_params3_t
1875 {
1877 uint32_t mode;
1879 float opacity;
1881 uint32_t mask_id;
1883 uint32_t blendif;
1885 float blendif_parameters[4 * DEVELOP_BLENDIF_SIZE];
1886 } dt_develop_blend_params3_t;
1887
1888 if(length != sizeof(dt_develop_blend_params3_t)) return 1;
1889
1890 dt_develop_blend_params3_t *o = (dt_develop_blend_params3_t *)old_params;
1892
1893 *n = default_display_blend_params; // start with a fresh copy of default parameters
1895 n->mask_mode |= ((o->blendif & (1u << DEVELOP_BLENDIF_active)) && (n->mask_mode == DEVELOP_MASK_ENABLED))
1897 : 0;
1898 n->blend_mode = _blend_legacy_blend_mode(o->mode);
1899 n->opacity = o->opacity;
1900 n->mask_id = o->mask_id;
1901 n->blendif = o->blendif & ~(1u << DEVELOP_BLENDIF_active); // knock out old unused "active" flag
1902 memcpy(n->blendif_parameters, o->blendif_parameters, sizeof(float) * 4 * DEVELOP_BLENDIF_SIZE);
1903
1904 return 0;
1905 }
1906
1907 if(old_version == 4 && new_version == 11)
1908 {
1910 typedef struct dt_develop_blend_params4_t
1911 {
1913 uint32_t mode;
1915 float opacity;
1917 uint32_t mask_id;
1919 uint32_t blendif;
1921 float radius;
1923 float blendif_parameters[4 * DEVELOP_BLENDIF_SIZE];
1924 } dt_develop_blend_params4_t;
1925
1926 if(length != sizeof(dt_develop_blend_params4_t)) return 1;
1927
1928 dt_develop_blend_params4_t *o = (dt_develop_blend_params4_t *)old_params;
1930
1931 *n = default_display_blend_params; // start with a fresh copy of default parameters
1933 n->mask_mode |= ((o->blendif & (1u << DEVELOP_BLENDIF_active)) && (n->mask_mode == DEVELOP_MASK_ENABLED))
1935 : 0;
1936 n->blend_mode = _blend_legacy_blend_mode(o->mode);
1937 n->opacity = o->opacity;
1938 n->mask_id = o->mask_id;
1939 n->blur_radius = o->radius;
1940 n->blendif = o->blendif & ~(1u << DEVELOP_BLENDIF_active); // knock out old unused "active" flag
1941 memcpy(n->blendif_parameters, o->blendif_parameters, sizeof(float) * 4 * DEVELOP_BLENDIF_SIZE);
1942
1943 return 0;
1944 }
1945
1946 if(old_version == 5 && new_version == 11)
1947 {
1949 typedef struct dt_develop_blend_params5_t
1950 {
1952 uint32_t mask_mode;
1954 uint32_t blend_mode;
1956 float opacity;
1958 uint32_t mask_combine;
1960 uint32_t mask_id;
1962 uint32_t blendif;
1964 float radius;
1966 uint32_t reserved[4];
1968 float blendif_parameters[4 * DEVELOP_BLENDIF_SIZE];
1969 } dt_develop_blend_params5_t;
1970
1971 if(length != sizeof(dt_develop_blend_params5_t)) return 1;
1972
1973 dt_develop_blend_params5_t *o = (dt_develop_blend_params5_t *)old_params;
1975
1976 *n = default_display_blend_params; // start with a fresh copy of default parameters
1977 n->mask_mode = o->mask_mode;
1978 n->blend_mode = _blend_legacy_blend_mode(o->blend_mode);
1979 n->opacity = o->opacity;
1980 n->mask_combine = o->mask_combine;
1981 n->mask_id = o->mask_id;
1982 n->blur_radius = o->radius;
1983 // this is needed as version 5 contained a bug which screwed up history
1984 // stacks of even older
1985 // versions. potentially bad history stacks can be identified by an active
1986 // bit no. 32 in blendif.
1987 n->blendif = (o->blendif & (1u << DEVELOP_BLENDIF_active) ? o->blendif | 31 : o->blendif)
1988 & ~(1u << DEVELOP_BLENDIF_active);
1989 memcpy(n->blendif_parameters, o->blendif_parameters, sizeof(float) * 4 * DEVELOP_BLENDIF_SIZE);
1990
1991 return 0;
1992 }
1993
1994 if(old_version == 6 && new_version == 11)
1995 {
1997 typedef struct dt_develop_blend_params6_t
1998 {
2000 uint32_t mask_mode;
2002 uint32_t blend_mode;
2004 float opacity;
2006 uint32_t mask_combine;
2008 uint32_t mask_id;
2010 uint32_t blendif;
2012 float radius;
2014 uint32_t reserved[4];
2016 float blendif_parameters[4 * DEVELOP_BLENDIF_SIZE];
2017 } dt_develop_blend_params6_t;
2018
2019 if(length != sizeof(dt_develop_blend_params6_t)) return 1;
2020
2021 dt_develop_blend_params6_t *o = (dt_develop_blend_params6_t *)old_params;
2023
2024 *n = default_display_blend_params; // start with a fresh copy of default parameters
2025 n->mask_mode = o->mask_mode;
2026 n->blend_mode = _blend_legacy_blend_mode(o->blend_mode);
2027 n->opacity = o->opacity;
2028 n->mask_combine = o->mask_combine;
2029 n->mask_id = o->mask_id;
2030 n->blur_radius = o->radius;
2031 n->blendif = o->blendif;
2032 memcpy(n->blendif_parameters, o->blendif_parameters, sizeof(float) * 4 * DEVELOP_BLENDIF_SIZE);
2033 return 0;
2034 }
2035
2036 if(old_version == 7 && new_version == 11)
2037 {
2039 typedef struct dt_develop_blend_params7_t
2040 {
2042 uint32_t mask_mode;
2044 uint32_t blend_mode;
2046 float opacity;
2048 uint32_t mask_combine;
2050 uint32_t mask_id;
2052 uint32_t blendif;
2054 float radius;
2056 uint32_t reserved[4];
2058 float blendif_parameters[4 * DEVELOP_BLENDIF_SIZE];
2059 } dt_develop_blend_params7_t;
2060
2061 if(length != sizeof(dt_develop_blend_params7_t)) return 1;
2062
2063 dt_develop_blend_params7_t *o = (dt_develop_blend_params7_t *)old_params;
2065
2066 *n = default_display_blend_params; // start with a fresh copy of default parameters
2067 n->mask_mode = o->mask_mode;
2068 n->blend_mode = _blend_legacy_blend_mode(o->blend_mode);
2069 n->opacity = o->opacity;
2070 n->mask_combine = o->mask_combine;
2071 n->mask_id = o->mask_id;
2072 n->blur_radius = o->radius;
2073 n->blendif = o->blendif;
2074 memcpy(n->blendif_parameters, o->blendif_parameters, sizeof(float) * 4 * DEVELOP_BLENDIF_SIZE);
2075 return 0;
2076 }
2077
2078 if(old_version == 8 && new_version == 11)
2079 {
2081 typedef struct dt_develop_blend_params8_t
2082 {
2084 uint32_t mask_mode;
2086 uint32_t blend_mode;
2088 float opacity;
2090 uint32_t mask_combine;
2092 uint32_t mask_id;
2094 uint32_t blendif;
2096 float feathering_radius;
2098 uint32_t feathering_guide;
2100 float blur_radius;
2102 float contrast;
2104 float brightness;
2106 uint32_t reserved[4];
2108 float blendif_parameters[4 * DEVELOP_BLENDIF_SIZE];
2109 } dt_develop_blend_params8_t;
2110
2111 if(length != sizeof(dt_develop_blend_params8_t)) return 1;
2112
2113 dt_develop_blend_params8_t *o = (dt_develop_blend_params8_t *)old_params;
2115
2116 *n = default_display_blend_params; // start with a fresh copy of default parameters
2117 n->mask_mode = o->mask_mode;
2118 n->blend_mode = _blend_legacy_blend_mode(o->blend_mode);
2119 n->opacity = o->opacity;
2120 n->mask_combine = o->mask_combine;
2121 n->mask_id = o->mask_id;
2122 n->blendif = o->blendif;
2123 n->feathering_radius = o->feathering_radius;
2124 n->feathering_guide = o->feathering_guide;
2125 n->blur_radius = o->blur_radius;
2126 n->contrast = o->contrast;
2127 n->brightness = o->brightness;
2128 memcpy(n->blendif_parameters, o->blendif_parameters, sizeof(float) * 4 * DEVELOP_BLENDIF_SIZE);
2129 return 0;
2130 }
2131
2132 if(old_version == 9 && new_version == 11)
2133 {
2135 typedef struct dt_develop_blend_params9_t
2136 {
2139 uint32_t mask_mode;
2141 uint32_t blend_mode;
2143 float opacity;
2145 uint32_t mask_combine;
2147 uint32_t mask_id;
2149 uint32_t blendif;
2151 float feathering_radius;
2153 uint32_t feathering_guide;
2155 float blur_radius;
2157 float contrast;
2159 float brightness;
2161 uint32_t reserved[4];
2163 float blendif_parameters[4 * DEVELOP_BLENDIF_SIZE];
2164 dt_dev_operation_t raster_mask_source;
2165 int raster_mask_instance;
2166 int raster_mask_id;
2167 gboolean raster_mask_invert;
2168 } dt_develop_blend_params9_t;
2169
2170 if(length != sizeof(dt_develop_blend_params9_t)) return 1;
2171
2172 dt_develop_blend_params9_t *o = (dt_develop_blend_params9_t *)old_params;
2174
2175 *n = default_display_blend_params; // start with a fresh copy of default parameters
2176 n->mask_mode = o->mask_mode;
2177 n->blend_mode = _blend_legacy_blend_mode(o->blend_mode);
2178 n->opacity = o->opacity;
2179 n->mask_combine = o->mask_combine;
2180 n->mask_id = o->mask_id;
2181 n->blendif = o->blendif;
2182 n->feathering_radius = o->feathering_radius;
2183 n->feathering_guide = o->feathering_guide;
2184 n->blur_radius = o->blur_radius;
2185 n->contrast = o->contrast;
2186 n->brightness = o->brightness;
2187 memcpy(n->blendif_parameters, o->blendif_parameters, sizeof(float) * 4 * DEVELOP_BLENDIF_SIZE);
2188 memcpy(n->raster_mask_source, o->raster_mask_source, sizeof(n->raster_mask_source));
2189 n->raster_mask_instance = o->raster_mask_instance;
2190 n->raster_mask_id = o->raster_mask_id;
2191 n->raster_mask_invert = o->raster_mask_invert;
2192 return 0;
2193 }
2194
2195 if(old_version == 10 && new_version == 11)
2196 {
2198 typedef struct dt_develop_blend_params10_t
2199 {
2202 uint32_t mask_mode;
2204 int32_t blend_cst;
2206 uint32_t blend_mode;
2208 float blend_parameter;
2210 float opacity;
2212 uint32_t mask_combine;
2214 uint32_t mask_id;
2216 uint32_t blendif;
2218 float feathering_radius;
2220 uint32_t feathering_guide;
2222 float blur_radius;
2224 float contrast;
2226 float brightness;
2228 uint32_t reserved[4];
2230 float blendif_parameters[4 * DEVELOP_BLENDIF_SIZE];
2231 float blendif_boost_factors[DEVELOP_BLENDIF_SIZE];
2232 dt_dev_operation_t raster_mask_source;
2233 int raster_mask_instance;
2234 int raster_mask_id;
2235 gboolean raster_mask_invert;
2236 } dt_develop_blend_params10_t;
2237
2238 if(length != sizeof(dt_develop_blend_params10_t)) return 1;
2239
2240 dt_develop_blend_params10_t *o = (dt_develop_blend_params10_t *)old_params;
2242
2243 *n = default_display_blend_params; // start with a fresh copy of default parameters
2244 n->mask_mode = o->mask_mode;
2245 n->blend_cst = o->blend_cst;
2246 n->blend_mode = _blend_legacy_blend_mode(o->blend_mode);
2247 n->blend_parameter = o->blend_parameter;
2248 n->opacity = o->opacity;
2249 n->mask_combine = o->mask_combine;
2250 n->mask_id = o->mask_id;
2251 n->blendif = o->blendif;
2252 n->feathering_radius = o->feathering_radius;
2253 n->feathering_guide = o->feathering_guide;
2254 n->blur_radius = o->blur_radius;
2255 n->contrast = o->contrast;
2256 n->brightness = o->brightness;
2257 // fix intermediate devel versions for details mask and initialize n->details to proper values if something was wrong
2258 memcpy(&n->details, &o->reserved, sizeof(float));
2259 if(isnan(n->details)) n->details = 0.0f;
2260 n->details = fminf(1.0f, fmaxf(-1.0f, n->details));
2261
2262 memcpy(n->blendif_parameters, o->blendif_parameters, sizeof(float) * 4 * DEVELOP_BLENDIF_SIZE);
2263 memcpy(n->blendif_boost_factors, o->blendif_boost_factors, sizeof(float) * DEVELOP_BLENDIF_SIZE);
2264 memcpy(n->raster_mask_source, o->raster_mask_source, sizeof(n->raster_mask_source));
2265 n->raster_mask_instance = o->raster_mask_instance;
2266 n->raster_mask_id = o->raster_mask_id;
2267 n->raster_mask_invert = o->raster_mask_invert;
2268 return 0;
2269 }
2270
2271 return 1;
2272}
2273
2274int dt_develop_blend_legacy_params_from_so(dt_iop_module_so_t *module_so, const void *const old_params,
2275 const int old_version, void *new_params, const int new_version,
2276 const int length)
2277{
2278 // we need a dt_iop_module_t for dt_develop_blend_legacy_params()
2279 dt_iop_module_t *module = (dt_iop_module_t *)calloc(1, sizeof(dt_iop_module_t));
2280 if(dt_iop_load_module_by_so(module, module_so, NULL))
2281 {
2282 dt_free(module);
2283 return 1;
2284 }
2285
2286 if(module->params_size == 0)
2287 {
2288 dt_iop_cleanup_module(module);
2289 dt_free(module);
2290 return 1;
2291 }
2292
2293 // convert the old blend params to new
2294 const int res = dt_develop_blend_legacy_params(module, old_params, old_version,
2295 new_params, dt_develop_blend_version(),
2296 length);
2297 dt_iop_cleanup_module(module);
2298 dt_free(module);
2299 return res;
2300}
2301
2302// tools/update_modelines.sh
2303// remove-trailing-space on;
2304/* Name tables for the persisted blend enums. Defined here rather than in blend_gui.c:
2305 * they map params values to translatable names, and backend consumers
2306 * (develop/supervisor.c) read them with no GUI loaded. */
2308 = { { NC_("blendmode", "normal"), DEVELOP_BLEND_NORMAL2 },
2309 { NC_("blendmode", "normal bounded"), DEVELOP_BLEND_BOUNDED },
2310 { NC_("blendmode", "lighten"), DEVELOP_BLEND_LIGHTEN },
2311 { NC_("blendmode", "darken"), DEVELOP_BLEND_DARKEN },
2312 { NC_("blendmode", "multiply"), DEVELOP_BLEND_MULTIPLY },
2313 { NC_("blendmode", "average"), DEVELOP_BLEND_AVERAGE },
2314 { NC_("blendmode", "addition"), DEVELOP_BLEND_ADD },
2315 { NC_("blendmode", "subtract"), DEVELOP_BLEND_SUBTRACT },
2316 { NC_("blendmode", "difference"), DEVELOP_BLEND_DIFFERENCE2 },
2317 { NC_("blendmode", "screen"), DEVELOP_BLEND_SCREEN },
2318 { NC_("blendmode", "overlay"), DEVELOP_BLEND_OVERLAY },
2319 { NC_("blendmode", "softlight"), DEVELOP_BLEND_SOFTLIGHT },
2320 { NC_("blendmode", "hardlight"), DEVELOP_BLEND_HARDLIGHT },
2321 { NC_("blendmode", "vividlight"), DEVELOP_BLEND_VIVIDLIGHT },
2322 { NC_("blendmode", "linearlight"), DEVELOP_BLEND_LINEARLIGHT },
2323 { NC_("blendmode", "pinlight"), DEVELOP_BLEND_PINLIGHT },
2324 { NC_("blendmode", "lightness"), DEVELOP_BLEND_LIGHTNESS },
2325 { NC_("blendmode", "chromaticity"), DEVELOP_BLEND_CHROMATICITY },
2326 { NC_("blendmode", "hue"), DEVELOP_BLEND_HUE },
2327 { NC_("blendmode", "color"), DEVELOP_BLEND_COLOR },
2328 { NC_("blendmode", "coloradjustment"), DEVELOP_BLEND_COLORADJUST },
2329 { NC_("blendmode", "Lab lightness"), DEVELOP_BLEND_LAB_LIGHTNESS },
2330 { NC_("blendmode", "Lab color"), DEVELOP_BLEND_LAB_COLOR },
2331 { NC_("blendmode", "Lab L-channel"), DEVELOP_BLEND_LAB_L },
2332 { NC_("blendmode", "Lab a-channel"), DEVELOP_BLEND_LAB_A },
2333 { NC_("blendmode", "Lab b-channel"), DEVELOP_BLEND_LAB_B },
2334 { NC_("blendmode", "HSV value"), DEVELOP_BLEND_HSV_VALUE },
2335 { NC_("blendmode", "HSV color"), DEVELOP_BLEND_HSV_COLOR },
2336 { NC_("blendmode", "RGB red channel"), DEVELOP_BLEND_RGB_R },
2337 { NC_("blendmode", "RGB green channel"), DEVELOP_BLEND_RGB_G },
2338 { NC_("blendmode", "RGB blue channel"), DEVELOP_BLEND_RGB_B },
2339 { NC_("blendmode", "divide"), DEVELOP_BLEND_DIVIDE },
2340 { NC_("blendmode", "geometric mean"), DEVELOP_BLEND_GEOMETRIC_MEAN },
2341 { NC_("blendmode", "harmonic mean"), DEVELOP_BLEND_HARMONIC_MEAN },
2342
2344 { NC_("blendmode", "difference (deprecated)"), DEVELOP_BLEND_DIFFERENCE },
2345 { NC_("blendmode", "subtract inverse (deprecated)"), DEVELOP_BLEND_SUBTRACT_INVERSE },
2346 { NC_("blendmode", "divide inverse (deprecated)"), DEVELOP_BLEND_DIVIDE_INVERSE },
2347 { "", 0 } };
2348
2350 = { { NC_("blendoperation", "normal"), 0 },
2351 { NC_("blendoperation", "reverse"), DEVELOP_BLEND_REVERSE },
2352 { "", 0 } };
2353
2355 = { { N_("default"), DEVELOP_BLEND_CS_NONE },
2356 { N_("RAW"), DEVELOP_BLEND_CS_RAW },
2357 { N_("Lab"), DEVELOP_BLEND_CS_LAB },
2358 { N_("RGB (display)"), DEVELOP_BLEND_CS_RGB_DISPLAY },
2359 { N_("RGB (scene)"), DEVELOP_BLEND_CS_RGB_SCENE },
2360 { "", 0 } };
2361
2363 = { { N_("None"), 0 },
2364 { N_("Uniform"), 1 },
2365 { N_("Parametric mask"), 2 },
2366 { N_("Drawn mask"), 3 },
2367 { N_("Drawn & parametric mask"), 4 },
2368 { N_("Reuse an existing mask"), 5 },
2369 { "", 0 } };
2370
2372 = { { N_("exclusive"), DEVELOP_COMBINE_NORM_EXCL },
2373 { N_("inclusive"), DEVELOP_COMBINE_NORM_INCL },
2374 { N_("exclusive & inverted"), DEVELOP_COMBINE_INV_EXCL },
2375 { N_("inclusive & inverted"), DEVELOP_COMBINE_INV_INCL },
2376 { "", 0 } };
2377
2379 = { { N_("output before blur"), DEVELOP_MASK_GUIDE_OUT_BEFORE_BLUR },
2380 { N_("input before blur"), DEVELOP_MASK_GUIDE_IN_BEFORE_BLUR },
2381 { N_("output after blur"), DEVELOP_MASK_GUIDE_OUT_AFTER_BLUR },
2382 { N_("input after blur"), DEVELOP_MASK_GUIDE_IN_AFTER_BLUR },
2383 { "", 0 } };
2384
2386 = { { N_("off"), DEVELOP_COMBINE_NORM },
2387 { N_("on"), DEVELOP_COMBINE_INV },
2388 { "", 0 } };
2389
2390// clang-format off
2391// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
2392// vim: shiftwidth=2 expandtab tabstop=2 cindent
2393// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
2394// 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
gboolean dt_develop_blend_colorspace_is_compatible(dt_iop_module_t *module, dt_develop_blend_colorspace_t cst)
Whether the given module may blend in the given color space.
Definition blend.c:158
static dt_develop_blend_colorspace_t _blend_default_module_blend_colorspace(dt_iop_module_t *module, gboolean is_scene_referred)
Definition blend.c:126
_develop_mask_post_processing
Definition blend.c:78
@ DEVELOP_MASK_POST_TONE_CURVE
Definition blend.c:83
@ DEVELOP_MASK_POST_FEATHER_IN
Definition blend.c:81
@ DEVELOP_MASK_POST_FEATHER_OUT
Definition blend.c:82
@ DEVELOP_MASK_POST_BLUR
Definition blend.c:80
@ DEVELOP_MASK_POST_NONE
Definition blend.c:79
void dt_develop_blend_init_blend_parameters(dt_develop_blend_params_t *blend_params, dt_develop_blend_colorspace_t cst)
Definition blend.c:212
static void _develop_blend_combine_masks(float *const restrict mask, const float *const restrict other_mask, const size_t buffsize)
Definition blend.c:642
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:1174
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:562
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:1026
const dt_develop_name_value_t dt_develop_invert_mask_names[]
Definition blend.c:2386
const dt_develop_name_value_t dt_develop_mask_mode_names[]
Definition blend.c:2363
void dt_develop_blend_free_cl_global(void)
Definition blend.c:1695
void dt_develop_blend_init_cl_global(void)
Definition blend.c:1664
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:468
static void _develop_blend_release_mask_entry(dt_pixel_cache_entry_t *mask_entry, const int created)
Definition blend.c:707
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:512
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:1730
static uint32_t _blend_legacy_blend_mode(uint32_t legacy_blend_mode)
Definition blend.c:1761
void dt_develop_blendif_process_parameters(float *const restrict parameters, const dt_develop_blend_params_t *const params)
Definition blend.c:253
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:234
int dt_develop_blendif_init_masking_profile(const struct dt_dev_pixelpipe_t *pipe, const struct dt_dev_pixelpipe_iop_t *piece, dt_iop_order_iccprofile_info_t *blending_profile, dt_develop_blend_colorspace_t cst)
Definition blend.c:361
static dt_blendop_cl_global_t * _blendop_cl_global
Definition blend.c:70
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:2274
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:400
dt_develop_blend_colorspace_t dt_develop_blend_default_module_blend_colorspace(dt_iop_module_t *module)
Definition blend.c:153
int dt_develop_blend_version(void)
Definition blend.c:1724
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:1788
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:539
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:301
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:719
static void _blend_init_blendif_boost_parameters(dt_develop_blend_params_t *blend_params, dt_develop_blend_colorspace_t cst)
Definition blend.c:188
static const char * dt_pipe_type_to_str(dt_dev_pixelpipe_type_t pipe_type)
Definition blend.c:86
const dt_develop_name_value_t dt_develop_blend_colorspace_names[]
Definition blend.c:2355
void dt_develop_blend_resolve_default_colorspace(dt_iop_module_t *module, dt_develop_blend_params_t *blend_params)
Replace DEVELOP_BLEND_CS_NONE, which stands for "whichever space this module blends in",...
Definition blend.c:205
gboolean dt_develop_blend_params_is_all_zero(const void *params, size_t length)
Definition blend.c:1751
static dt_develop_blend_params_t _default_blendop_params
Definition blend.c:104
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:675
dt_blendop_cl_global_t * dt_develop_blend_get_cl_global(void)
Definition blend.c:72
const dt_develop_name_value_t dt_develop_blend_mode_flag_names[]
Definition blend.c:2350
static void _develop_blend_process_free_region(float *const restrict input)
Definition blend.c:534
static float _detail_mask_threshold(const float level, const gboolean detail)
Definition blend.c:394
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:602
const dt_develop_name_value_t dt_develop_combine_masks_names[]
Definition blend.c:2372
const dt_develop_name_value_t dt_develop_blend_mode_names[]
Definition blend.c:2308
void dt_develop_blend_init_blendif_parameters(dt_develop_blend_params_t *blend_params, dt_develop_blend_colorspace_t cst)
Definition blend.c:220
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:652
const dt_develop_name_value_t dt_develop_feathering_guide_names[]
Definition blend.c:2379
static void _blend_process_cl_exchange(cl_mem *a, cl_mem *b)
Definition blend.c:1167
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:136
@ DEVELOP_MASK_GUIDE_IN_AFTER_BLUR
Definition blend.h:137
@ DEVELOP_MASK_GUIDE_OUT_AFTER_BLUR
Definition blend.h:138
@ DEVELOP_MASK_GUIDE_IN_BEFORE_BLUR
Definition blend.h:135
dt_develop_blend_colorspace_t
Definition blend.h:53
@ DEVELOP_BLEND_CS_NONE
Definition blend.h:54
@ DEVELOP_BLEND_CS_LAB
Definition blend.h:56
@ DEVELOP_BLEND_CS_RGB_SCENE
Definition blend.h:58
@ DEVELOP_BLEND_CS_RGB_DISPLAY
Definition blend.h:57
@ DEVELOP_BLEND_CS_RAW
Definition blend.h:55
@ DEVELOP_COMBINE_INV
Definition blend.h:123
@ DEVELOP_COMBINE_NORM
Definition blend.h:122
@ DEVELOP_COMBINE_INCL
Definition blend.h:125
@ DEVELOP_COMBINE_MASKS_POS
Definition blend.h:126
@ DEVELOP_COMBINE_NORM_INCL
Definition blend.h:128
@ DEVELOP_COMBINE_INV_INCL
Definition blend.h:130
@ DEVELOP_COMBINE_INV_EXCL
Definition blend.h:129
@ DEVELOP_COMBINE_NORM_EXCL
Definition blend.h:127
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:176
@ DEVELOP_BLENDIF_A_in
Definition blend.h:144
@ DEVELOP_BLENDIF_Lab_MASK
Definition blend.h:190
@ DEVELOP_BLENDIF_Jz_out
Definition blend.h:179
@ DEVELOP_BLENDIF_B_in
Definition blend.h:145
@ DEVELOP_BLENDIF_Cz_out
Definition blend.h:180
@ DEVELOP_BLENDIF_Jz_in
Definition blend.h:175
@ DEVELOP_BLENDIF_A_out
Definition blend.h:148
@ DEVELOP_BLENDIF_B_out
Definition blend.h:149
@ DEVELOP_BLENDIF_active
Definition blend.h:186
@ DEVELOP_BLENDIF_RGB_MASK
Definition blend.h:191
#define DEVELOP_BLENDIF_PARAMETER_ITEMS
Definition blend.h:353
@ DEVELOP_BLEND_LIGHTEN
Definition blend.h:65
@ DEVELOP_BLEND_COLOR
Definition blend.h:82
@ DEVELOP_BLEND_CHROMATICITY
Definition blend.h:80
@ DEVELOP_BLEND_DIFFERENCE
Definition blend.h:71
@ DEVELOP_BLEND_RGB_B
Definition blend.h:98
@ DEVELOP_BLEND_LIGHTNESS
Definition blend.h:79
@ DEVELOP_BLEND_BOUNDED
Definition blend.h:88
@ DEVELOP_BLEND_SUBTRACT
Definition blend.h:70
@ DEVELOP_BLEND_MODE_MASK
Definition blend.h:107
@ DEVELOP_BLEND_DIVIDE_INVERSE
Definition blend.h:102
@ DEVELOP_BLEND_MULTIPLY_REVERSE_OBSOLETE
Definition blend.h:99
@ DEVELOP_BLEND_NORMAL2
Definition blend.h:87
@ DEVELOP_BLEND_HARDLIGHT
Definition blend.h:75
@ DEVELOP_BLEND_HUE
Definition blend.h:81
@ DEVELOP_BLEND_OVERLAY
Definition blend.h:73
@ DEVELOP_BLEND_RGB_R
Definition blend.h:96
@ DEVELOP_BLEND_LAB_A
Definition blend.h:94
@ DEVELOP_BLEND_LAB_COLOR
Definition blend.h:90
@ DEVELOP_BLEND_REVERSE
Definition blend.h:106
@ DEVELOP_BLEND_DISABLED_OBSOLETE
Definition blend.h:63
@ DEVELOP_BLEND_AVERAGE
Definition blend.h:68
@ DEVELOP_BLEND_DIVIDE
Definition blend.h:101
@ DEVELOP_BLEND_HSV_COLOR
Definition blend.h:92
@ DEVELOP_BLEND_MULTIPLY
Definition blend.h:67
@ DEVELOP_BLEND_SCREEN
Definition blend.h:72
@ DEVELOP_BLEND_HARMONIC_MEAN
Definition blend.h:104
@ DEVELOP_BLEND_PINLIGHT
Definition blend.h:78
@ DEVELOP_BLEND_HSV_VALUE
Definition blend.h:91
@ DEVELOP_BLEND_LAB_L
Definition blend.h:93
@ DEVELOP_BLEND_LINEARLIGHT
Definition blend.h:77
@ DEVELOP_BLEND_ADD
Definition blend.h:69
@ DEVELOP_BLEND_VIVIDLIGHT
Definition blend.h:76
@ DEVELOP_BLEND_GEOMETRIC_MEAN
Definition blend.h:103
@ DEVELOP_BLEND_NORMAL_OBSOLETE
Definition blend.h:64
@ DEVELOP_BLEND_SOFTLIGHT
Definition blend.h:74
@ DEVELOP_BLEND_UNBOUNDED_OBSOLETE
Definition blend.h:84
@ DEVELOP_BLEND_COLORADJUST
Definition blend.h:85
@ DEVELOP_BLEND_DARKEN
Definition blend.h:66
@ DEVELOP_BLEND_INVERSE_OBSOLETE
Definition blend.h:83
@ DEVELOP_BLEND_LAB_B
Definition blend.h:95
@ DEVELOP_BLEND_LAB_LIGHTNESS
Definition blend.h:89
@ DEVELOP_BLEND_DIFFERENCE2
Definition blend.h:86
@ DEVELOP_BLEND_SUBTRACT_INVERSE
Definition blend.h:100
@ DEVELOP_BLEND_RGB_G
Definition blend.h:97
@ DEVELOP_MASK_RASTER
Definition blend.h:116
@ DEVELOP_MASK_PARAMETRIC
Definition blend.h:115
@ DEVELOP_MASK_DISABLED
Definition blend.h:112
@ DEVELOP_MASK_ENABLED
Definition blend.h:113
@ DEVELOP_MASK_SHAPE
Definition blend.h:114
#define DEVELOP_BLEND_VERSION
Definition blend.h:50
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
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)
free parameters build with the previous function.
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)
build the required parameters for a kernel that uses a profile info.
static const float x
const float threshold
const dt_colormatrix_t dt_aligned_pixel_t out
const float top
static const dt_colormatrix_t M
void dt_control_alert(const char *title, const char *message, const char *item)
Tell the user something that must not go unseen: what it says stays true after a toast would have fad...
Definition control.c:883
void dt_masks_blur_9x9_coeff(float *c, const float sigma)
Definition detail.c:165
void dt_masks_calc_detail_mask(float *const restrict src, float *const restrict out, float *const restrict tmp, const int width, const int height, const float threshold, const gboolean detail)
Definition detail.c:331
dt_ioppr_profile_stage_t dt_ioppr_get_module_profile_stage(const dt_iop_module_t *module)
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)
__DT_CLONE_TARGETS__ dt_iop_order_iccprofile_info_t * dt_ioppr_get_iop_work_profile_info(struct dt_iop_module_t *module, GList *iop_list)
@ DT_IOPPR_PROFILE_STAGE_WORK
dt_dev_pixelpipe_display_mask_t
Definition develop.h:121
@ DT_DEV_PIXELPIPE_DISPLAY_CHANNEL
Definition develop.h:124
@ DT_DEV_PIXELPIPE_DISPLAY_ANY
Definition develop.h:143
@ DT_DEV_PIXELPIPE_DISPLAY_MASK
Definition develop.h:123
@ DT_DEV_PIXELPIPE_DISPLAY_NONE
Definition develop.h:122
const int res
Definition dtpthread.h:351
static gboolean dt_iop_colorspace_is_rgb(const dt_iop_colorspace_type_t cst)
Definition format.h:75
@ IOP_CS_RGB_DISPLAY
Definition format.h:71
void dt_gaussian_free(dt_gaussian_t *g)
Definition gaussian.c:335
void dt_gaussian_free_cl(dt_gaussian_cl_t *g)
Definition gaussian.c:365
cl_int dt_gaussian_blur_cl(dt_gaussian_cl_t *g, cl_mem dev_in, cl_mem dev_out)
Definition gaussian.c:453
__DT_CLONE_TARGETS__ void dt_gaussian_blur(dt_gaussian_t *g, const float *const in, float *const out)
Definition gaussian.c:176
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:376
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:127
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)
char dt_dev_operation_t[20]
The string identifying an operation in the history stack ("exposure", "colorbalancergb",...
Definition history.h:50
__DT_CLONE_TARGETS__ void dt_iop_image_mul_const(float *const buf, const float mul_value, const size_t width, const size_t height, const size_t ch)
Definition imagebuf.c:355
__DT_CLONE_TARGETS__ void dt_iop_image_invert(float *const buf, const float max_value, const size_t width, const size_t height, const size_t ch)
Definition imagebuf.c:330
__DT_CLONE_TARGETS__ void dt_iop_image_fill(float *const buf, const float fill_value, const size_t width, const size_t height, const size_t ch)
Definition imagebuf.c:218
__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:193
gboolean dt_iop_is_raster_mask_used(dt_iop_module_t *module, int id)
Definition imageop.c:1841
void dt_iop_cleanup_module(dt_iop_module_t *module)
Definition imageop.c:1113
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:510
@ IOP_FLAGS_SUPPORTS_BLENDING
Definition imageop.h:186
@ IOP_FLAGS_NO_MASKS
Definition imageop.h:194
void *const ovoid
static float kernel(const float *x, const float *y)
static const dt_dev_pixelpipe_t * pipe
Definition layers.h:49
static const dt_dev_pixelpipe_t const dt_dev_pixelpipe_iop_t * piece
Definition layers.h:50
static const dt_iop_drawlayer_params_t * params
Definition layers.h:80
#define DEVELOP_BLENDIF_SIZE
Definition lightroom.c:236
@ DT_DEBUG_OPENCL
Definition logging.h:57
@ DT_DEBUG_MASKS
Definition logging.h:62
int32_t dt_get_debug_flags(void)
Definition darktable.c:2094
void dt_print(dt_debug_thread_t thread, const char *msg,...) __attribute__((format(printf
Print to stdout when thread is enabled, prefixed with seconds since startup.
float *const restrict const size_t k
float *const restrict const size_t const size_t ch
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
Definition macros.h:96
@ DT_MASKS_RASTER_ERROR
Definition masks.h:316
dt_masks_form_t * dt_masks_get_from_id_ext(GList *forms, int id)
Definition masks.c:915
dt_masks_form_t * dt_masks_get_from_id(dt_develop_t *dev, int id)
Definition masks.c:925
dt_masks_raster_result_t dt_masks_group_render_roi(dt_iop_module_t *module, const 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:963
The detail-mask pixel math: a Scharr-style detail estimate over a raw or scene-referred buffer,...
@ DT_MASKS_GROUP
Definition masks_types.h:66
static float clamp_range_f(const float x, const float low, const float high)
Definition math.h:98
float DT_ALIGNED_ARRAY dt_colormatrix_t[4][4]
Definition matrices.h:34
#define DT_ALIGNED_ARRAY
Align an object on a cacheline boundary, so AVX2 can load it whole.
Definition mem_alloc.h:80
#define dt_free(ptr)
g_free() ptr and set it to NULL, skipping both if it is already NULL.
Definition mem_alloc.h:171
uint32_t width
Definition mipmap_cache.c:0
uint32_t height
Definition mipmap_cache.c:1
float iscale
Definition mipmap_cache.c:2
#define o
int dt_opencl_enqueue_kernel_2d(const int dev, const int kernel, const size_t *sizes)
Definition opencl.c:2612
void * dt_opencl_alloc_device_buffer(const int devid, const size_t size)
Definition opencl.c:3028
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:2639
void * dt_opencl_alloc_device(const int devid, const int width, const int height, const int bpp)
Definition opencl.c:2952
int dt_opencl_create_kernel(const int prog, const char *name)
Definition opencl.c:2506
void * dt_opencl_copy_host_to_device_constant(const int devid, const size_t size, void *host)
Definition opencl.c:2808
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:2737
void dt_opencl_free_kernel(const int kernel)
Definition opencl.c:2549
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:2603
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:2645
void dt_opencl_release_mem_object(cl_mem mem)
Definition opencl.c:2863
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:2692
#define ROUNDUPDHT(a, b)
Definition opencl.h:86
#define ROUNDUPDWD(a, b)
Definition opencl.h:85
#define __OMP_PARALLEL_FOR__(...)
Definition openmp.h:95
#define __OMP_FOR_SIMD__(...)
Definition openmp.h:97
#define __OMP_PARALLEL_FOR_SIMD__(...)
Definition openmp.h:96
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:40
@ DT_DEV_PIXELPIPE_THUMBNAIL
Definition pixelpipe.h:45
@ DT_DEV_PIXELPIPE_EXPORT
Definition pixelpipe.h:42
@ DT_DEV_PIXELPIPE_PREVIEW
Definition pixelpipe.h:44
@ DT_DEV_PIXELPIPE_FULL
Definition pixelpipe.h:43
void dt_dev_pixelpipe_cache_wrlock_entry(gboolean lock, dt_pixel_cache_entry_t *cache_entry)
Lock or release the write lock on the entry.
void dt_dev_pixelpipe_cache_ref_count_entry(gboolean lock, dt_pixel_cache_entry_t *cache_entry)
Take or release one reference on a cache line. A referenced line is never evicted,...
int dt_dev_pixelpipe_cache_get(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.
void dt_dev_pixelpipe_cache_flag_auto_destroy(dt_pixel_cache_entry_t *cache_entry)
Flag a cache line as disposable (auto_destroy), for short-lived lines nothing will need again: the re...
#define dt_pixelpipe_cache_alloc_align_float_cache(pixels, id)
#define dt_pixelpipe_cache_free_align(mem)
#define dt_pixelpipe_cache_alloc_align_float(pixels, pipe)
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)
static const dt_aligned_pixel_simd_t value
Definition simd.h:144
const float sigma
unsigned __int64 uint64_t
Definition strptime.c:75
int kernel_blendop_mask_rgb_jzczhz
Definition blend.h:245
int kernel_blendop_display_channel
Definition blend.h:252
int kernel_blendop_rgb_jzczhz
Definition blend.h:249
int kernel_blendop_mask_rgb_hsl
Definition blend.h:244
int kernel_blendop_mask_tone_curve
Definition blend.h:250
The device-side view of a dt_iop_order_iccprofile_info_t: the scalar fields only.
dt_atomic_uint64 hash
dt_dev_pixelpipe_type_t type
gboolean store_all_raster_masks
GArray * raster_mask_hashes
struct dt_develop_t * dev
float blendif_parameters[4 *DEVELOP_BLENDIF_SIZE]
Definition blend.h:231
float blendif_boost_factors[DEVELOP_BLENDIF_SIZE]
Definition blend.h:232
int32_t gui_attached
Definition develop.h:167
dt_image_t image_storage
Definition develop.h:225
GList * iop
Definition develop.h:269
struct dt_iop_module_t * gui_module
Definition develop.h:170
struct dt_dev_pixelpipe_t * pipe
Definition develop.h:214
char fullpath[DT_PATH_MAX]
Definition image.h:396
struct dt_develop_t * dev
Definition imageop.h:311
int request_mask_display
Definition imageop.h:276
struct dt_iop_module_t::@23::@24 source
struct dt_iop_module_t::@23::@25 sink
struct dt_iop_module_t::@23 raster_mask
dt_dev_operation_t op
Definition imageop.h:259
A profile reduced to the arithmetic the pixel loop can run: two matrices and six tone-curve LUTs,...
dt_colormatrix_t matrix_out
XYZ (D50) -> RGB, row-major; the inverse of matrix_in.
dt_colormatrix_t matrix_in
RGB -> XYZ (D50), row-major. matrix_in[1][*] is the luminance row. NaN in [0][0] marks the whole prof...
Region of interest passed through the pixelpipe.
Definition format.h:49
double scale
Definition format.h:51
int width
Definition format.h:50
int height
Definition format.h:50
dt_masks_type_t type
Definition masks.h:254
GList * points
Definition masks.h:253
uint64_t dt_supervisor_node_key(const int pipe_type, const char *op_name, const int multi_priority)
Definition supervisor.c:165
void dt_supervisor_cacheline_create(const uint64_t hash, const uint64_t node_hash, const uint64_t param_hash, const uint64_t input_hash, const char *op_name, const int multi_priority, const int iop_order, const int pipe_type, const int32_t imgid, const int roi_w, const int roi_h, const int devid, const size_t size, const char *name)
Definition supervisor.c:891
static gboolean dt_supervisor_active(void)
Definition supervisor.h:95
#define MAX(a, b)
Definition thinplate.c:29
static const int mask_id
Definition useless.c:215
Telling the user something happened.