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,
254 const dt_develop_blend_params_t *const params)
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
302 const dt_develop_blend_params_t *params,
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)
374 ? dt_ioppr_get_pipe_current_profile_info(piece->module, pipe)
375 : dt_ioppr_get_iop_work_profile_info(piece->module, piece->module->dev->iop);
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
428 tmp = dt_pixelpipe_cache_alloc_align_float(bufsize, pipe);
429 lum = dt_pixelpipe_cache_alloc_align_float(bufsize, pipe);
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:
460 dt_pipeline_message(_("detail mask blending error"));
464}
465
467 const dt_dev_pixelpipe_iop_t *const piece,
468 _develop_mask_post_processing operations[3])
469{
470 const gboolean mask_feather = params->feathering_radius > 0.1f && piece->dsc_in.channels >= 3;
471 const gboolean mask_blur = params->blur_radius > 0.1f;
472 const gboolean mask_tone_curve = fabsf(params->contrast) >= 0.01f || fabsf(params->brightness) >= 0.01f;
473 const gboolean mask_feather_before = params->feathering_guide == DEVELOP_MASK_GUIDE_IN_BEFORE_BLUR
474 || params->feathering_guide == DEVELOP_MASK_GUIDE_OUT_BEFORE_BLUR;
475 const gboolean mask_feather_out = params->feathering_guide == DEVELOP_MASK_GUIDE_OUT_BEFORE_BLUR
476 || params->feathering_guide == DEVELOP_MASK_GUIDE_OUT_AFTER_BLUR;
477 const float opacity = fminf(fmaxf(params->opacity / 100.0f, 0.0f), 1.0f);
478
479 memset(operations, 0, sizeof(_develop_mask_post_processing) * 3);
480 size_t index = 0;
481
482 if(mask_feather)
483 {
484 if(mask_blur && mask_feather_before)
485 {
486 operations[index++] = mask_feather_out ? DEVELOP_MASK_POST_FEATHER_OUT : DEVELOP_MASK_POST_FEATHER_IN;
487 operations[index++] = DEVELOP_MASK_POST_BLUR;
488 }
489 else
490 {
491 if(mask_blur)
492 operations[index++] = DEVELOP_MASK_POST_BLUR;
493 operations[index++] = mask_feather_out ? DEVELOP_MASK_POST_FEATHER_OUT : DEVELOP_MASK_POST_FEATHER_IN;
494 }
495 }
496 else if(mask_blur)
497 {
498 operations[index++] = DEVELOP_MASK_POST_BLUR;
499 }
500
501 if(mask_tone_curve && opacity > 1e-4f)
502 {
503 operations[index++] = DEVELOP_MASK_POST_TONE_CURVE;
504 }
505
506 return index;
507}
508
509
510static inline float *_develop_blend_process_copy_region(const float *const restrict input, const size_t iwidth,
511 const size_t xoffs, const size_t yoffs,
512 const size_t owidth, const size_t oheight)
513{
514 const size_t ioffset = yoffs * iwidth + xoffs;
515 float *const restrict output =
517 if(IS_NULL_PTR(output))
518 {
519 return NULL;
520 }
522 for(size_t y = 0; y < oheight; y++)
523 {
524 const size_t iindex = y * iwidth + ioffset;
525 const size_t oindex = y * owidth;
526 memcpy(output + oindex, input + iindex, sizeof(float) * owidth);
527 }
528
529 return output;
530}
531
532static inline void _develop_blend_process_free_region(float *const restrict input)
533{
535}
536
538 const dt_iop_module_t *const self)
539{
540 if(IS_NULL_PTR(params) || IS_NULL_PTR(self)) return NULL;
541
542 const dt_iop_module_t *source = self->raster_mask.sink.source;
543 if(source && !strcmp(source->op, params->raster_mask_source)
544 && source->multi_priority == params->raster_mask_instance)
545 return source;
546
547 if(IS_NULL_PTR(self->dev) || params->raster_mask_source[0] == '\0') return NULL;
548
549 for(GList *iter = g_list_first(self->dev->iop); iter; iter = g_list_next(iter))
550 {
551 const dt_iop_module_t *candidate = (const dt_iop_module_t *)iter->data;
552 if(!strcmp(candidate->op, params->raster_mask_source)
553 && candidate->multi_priority == params->raster_mask_instance)
554 return candidate;
555 }
556
557 return NULL;
558}
559
561 dt_iop_module_t *self,
562 dt_dev_pixelpipe_t *pipe,
563 const dt_dev_pixelpipe_iop_t *piece,
564 float *const restrict mask,
565 const size_t owidth,
566 const size_t oheight,
567 int *const raster_error)
568{
569 int local_raster_error = 0;
570 const dt_iop_module_t *raster_source = _develop_blend_get_raster_source_module(params, self);
571 float *raster_mask = raster_source
572 ? dt_dev_get_raster_mask(pipe, raster_source, params->raster_mask_id,
573 self, &local_raster_error)
574 : NULL;
575
576 if(!IS_NULL_PTR(raster_mask))
577 {
578 if(params->raster_mask_invert)
579 {
580 __OMP_FOR_SIMD__(aligned(mask, raster_mask:64) )
581 for(size_t i = 0; i < owidth * oheight; i++)
582 mask[i] = 1.0f - raster_mask[i];
583 }
584 else
585 {
586 dt_iop_image_scaled_copy(mask, raster_mask, 1.0f, owidth, oheight, 1);
587 }
588
590 }
591 else
592 {
593 const float value = params->raster_mask_invert ? 0.0f : 1.0f;
594 dt_iop_image_fill(mask, value, owidth, oheight, 1);
595 }
596
597 if(!IS_NULL_PTR(raster_error)) *raster_error = local_raster_error;
598}
599
601 dt_iop_module_t *self,
602 dt_dev_pixelpipe_t *pipe,
603 const dt_dev_pixelpipe_iop_t *piece,
604 const struct dt_iop_roi_t *const roi_out,
605 float *const restrict mask,
606 const size_t owidth,
607 const size_t oheight)
608{
609 /* Resolve through the pipe's refcounted forms snapshot, never the live dev->forms: this runs
610 * on the worker while the GUI thread moves the very shape being rendered (see the retouch
611 * rule in CLAUDE.md). The live list is only a fallback for a pipe that took no snapshot. */
612 dt_masks_form_t *form = (!IS_NULL_PTR(pipe) && !IS_NULL_PTR(pipe->forms))
613 ? dt_masks_get_from_id_ext(pipe->forms, params->mask_id)
614 : dt_masks_get_from_id(self->dev, params->mask_id);
615
616 if(form && (!(self->flags() & IOP_FLAGS_NO_MASKS)) && (params->mask_mode & DEVELOP_MASK_SHAPE))
617 {
618 /* EMPTY is not a failure: the fold zeroes the buffer when no shape contributed, and a
619 * zero drawn mask is a legitimate state to blend with. Only ERROR leaves it undefined. */
620 if(dt_masks_group_render_roi(self, pipe, piece, form, roi_out, mask) == DT_MASKS_RASTER_ERROR)
621 return 1;
622
623 if(params->mask_combine & DEVELOP_COMBINE_MASKS_POS)
624 dt_iop_image_invert(mask, 1.0f, owidth, oheight, 1);
625 }
626 else if((!(self->flags() & IOP_FLAGS_NO_MASKS)) && (params->mask_mode & DEVELOP_MASK_SHAPE))
627 {
628 const float fill = (params->mask_combine & DEVELOP_COMBINE_MASKS_POS) ? 0.0f : 1.0f;
629 dt_iop_image_fill(mask, fill, owidth, oheight, 1);
630 }
631 else
632 {
633 const float fill = (params->mask_combine & DEVELOP_COMBINE_INCL) ? 0.0f : 1.0f;
634 dt_iop_image_fill(mask, fill, owidth, oheight, 1);
635 }
636
637 return 0;
638}
639
640static void _develop_blend_combine_masks(float *const restrict mask,
641 const float *const restrict other_mask,
642 const size_t buffsize)
643{
644 __OMP_FOR_SIMD__(aligned(mask, other_mask:64) )
645 for(size_t i = 0; i < buffsize; i++)
646 mask[i] *= other_mask[i];
647}
648
649
650static int _develop_blend_process_feather(const float *const guide, float *const mask, const size_t width,
651 const size_t height, const int ch, const float guide_weight,
652 const float feathering_radius, const float scale)
653{
654 const float sqrt_eps = 1.f;
655 int w = (int)(2 * feathering_radius * scale + 0.5f);
656 if(w < 1) w = 1;
657
658 float *const restrict mask_bak =
660 if(IS_NULL_PTR(mask_bak)) return 1;
661
662 memcpy(mask_bak, mask, sizeof(float) * width * height);
663 if(guided_filter(guide, mask_bak, mask, width, height, ch, w, sqrt_eps, guide_weight, 0.f, 1.f) != 0)
664 {
666 return 1;
667 }
669 return 0;
670}
671
672
673static void _develop_blend_process_mask_tone_curve(float *const restrict mask, const size_t buffsize,
674 const float contrast, const float brightness,
675 const float opacity)
676{
677 const float mask_epsilon = 16 * FLT_EPSILON; // empirical mask threshold for fully transparent masks
678 const float e = expf(3.f * contrast);
679 __OMP_PARALLEL_FOR_SIMD__(aligned(mask:64))
680 for(size_t k = 0; k < buffsize; k++)
681 {
682 float x = mask[k] / opacity;
683 x = 2.f * x - 1.f;
684 if (1.f - brightness <= 0.f)
685 x = mask[k] <= mask_epsilon ? -1.f : 1.f;
686 else if (1.f + brightness <= 0.f)
687 x = mask[k] >= 1.f - mask_epsilon ? 1.f : -1.f;
688 else if (brightness > 0.f)
689 {
690 x = (x + brightness) / (1.f - brightness);
691 x = fminf(x, 1.f);
692 }
693 else
694 {
695 x = (x + brightness) / (1.f + brightness);
696 x = fmaxf(x, -1.f);
697 }
698 mask[k] = clamp_range_f(
699 ((x * e / (1.f + (e - 1.f) * fabsf(x))) / 2.f + 0.5f) * opacity, 0.f, 1.f);
700 }
701}
702
703
705 const struct dt_dev_pixelpipe_iop_t *piece, const void *const ivoid,
706 void *const ovoid)
707{
708 const dt_iop_roi_t *const roi_in = &piece->roi_in;
709 const dt_iop_roi_t *const roi_out = &piece->roi_out;
710 if(pipe->bypass_blendif && self->dev->gui_attached && (self == self->dev->gui_module)) return 0;
711
712 const dt_develop_blend_params_t *const d = (const dt_develop_blend_params_t *const)piece->blendop_data;
713 if(IS_NULL_PTR(d)) return 0;
714
715 gboolean top_enabled = FALSE;
716 gboolean raster_used = FALSE;
717 gboolean drawn_used = FALSE;
718 gboolean parametric_used = FALSE;
719 dt_develop_blend_get_mask_usage(self, d, &top_enabled, &raster_used, &drawn_used, &parametric_used);
720 if(!top_enabled) return 0;
721 // A mask preview request must also be honored when every sub-mask is neutral.
722 // In that case no raster/drawn/parametric mask is "used", but the effective
723 // blend mask is still the uniform opacity mask written into alpha below.
724 const gboolean preview_mask_mode = top_enabled;
725
726 const size_t ch = piece->dsc_in.channels; // the number of channels in the buffer
727 const int xoffs = roi_out->x - roi_in->x;
728 const int yoffs = roi_out->y - roi_in->y;
729 const int iwidth = roi_in->width;
730 const int iheight = roi_in->height;
731 const int owidth = roi_out->width;
732 const int oheight = roi_out->height;
733 const size_t buffsize = (size_t)owidth * oheight;
734 const float iscale = roi_in->scale;
735 const float oscale = roi_out->scale;
736 const gboolean rois_equal = iwidth == owidth || iheight == oheight || xoffs == 0 || yoffs == 0;
737
738 // In most cases of blending-enabled modules input and output of the module have
739 // the exact same dimensions. Only in very special cases we allow a module's input
740 // to exceed its output. This is namely the case for the spot removal module where
741 // the source of a patch might lie outside the roi of the output image. Therefore:
742 // We can only handle blending if roi_out and roi_in have the same scale and
743 // if roi_out fits into the area given by roi_in. xoffs and yoffs describe the relative
744 // offset of the input image to the output image.
745 if(oscale != iscale || xoffs < 0 || yoffs < 0
746 || ((xoffs > 0 || yoffs > 0) && (owidth + xoffs > iwidth || oheight + yoffs > iheight)))
747 {
748 dt_pipeline_message(_("skipped blending in module '%s': roi's do not match"), self->op);
749 return 0;
750 }
751
752 // does user want us to display a specific channel?
753 const dt_dev_pixelpipe_display_mask_t request_mask_display =
754 (self->dev->gui_attached && (self == self->dev->gui_module) && (pipe == self->dev->pipe)
755 && preview_mask_mode)
758
759 // get channel max values depending on colorspace
760 const dt_develop_blend_colorspace_t blend_csp = d->blend_cst;
762
763 // obtaining the list of mask operations to perform
764 _develop_mask_post_processing post_operations[3];
765 const size_t post_operations_size = _develop_mask_get_post_operations(d, piece, post_operations);
766
767 // get the clipped opacity value 0 - 1
768 const float opacity = fminf(fmaxf(d->opacity / 100.0f, 0.0f), 1.0f);
769
770 // allocate space for blend mask
771 float *const restrict _mask = dt_pixelpipe_cache_alloc_align_float(buffsize, pipe);
772 if(IS_NULL_PTR(_mask))
773 {
774 dt_pipeline_message(_("could not allocate buffer for blending"));
775 return 1;
776 }
777 int raster_error = 0;
778 float *const restrict mask = _mask;
779 const gboolean use_masks = raster_used || drawn_used || parametric_used;
780 const gboolean raster_only = raster_used && !drawn_used && !parametric_used;
781
782 if(!use_masks)
783 {
784 // blend uniformly (no drawn or parametric mask)
785 dt_iop_image_fill(mask,opacity,owidth,oheight,1); //mask[k] = opacity;
786 }
787 else if(raster_only)
788 {
789 /* use a raster mask from another module earlier in the pipe */
790 _develop_blend_init_raster_mask(d, self, pipe, piece, mask, owidth, oheight, &raster_error);
791 dt_iop_image_mul_const(mask, opacity, owidth, oheight, 1);
792 }
793 else
794 {
795 if(!raster_used && !drawn_used)
796 {
797 // Parametric-only blending has no raster/drawn form mask to seed `mask`.
798 // The combination code below loops on parametric channels and composes them
799 // with that form mask, so initialize it as the neutral value of the chosen
800 // mask-combine operator.
801 const float fill = (d->mask_combine & DEVELOP_COMBINE_INCL) ? 0.0f : 1.0f;
802 dt_iop_image_fill(mask, fill, owidth, oheight, 1);
803 }
804 else if(raster_used)
805 {
806 _develop_blend_init_raster_mask(d, self, pipe, piece, mask, owidth, oheight, &raster_error);
807
808 if(drawn_used)
809 {
810 float *const restrict drawn_mask = dt_pixelpipe_cache_alloc_align_float(buffsize, pipe);
811 if(IS_NULL_PTR(drawn_mask))
812 {
813 dt_pipeline_message(_("could not allocate buffer for blending"));
815 return 1;
816 }
817
818 if(_develop_blend_init_drawn_mask(d, self, pipe, piece, roi_out, drawn_mask, owidth, oheight) != 0)
819 {
822 return 1;
823 }
824
825 _develop_blend_combine_masks(mask, drawn_mask, buffsize);
827 }
828 }
829 else if(drawn_used
830 && _develop_blend_init_drawn_mask(d, self, pipe, piece, roi_out, mask, owidth, oheight) != 0)
831 {
833 return 1;
834 }
835
836 _refine_with_detail_mask(self, pipe, piece, mask, d->details);
837
838 // get parametric mask (if any) and apply global opacity
839 switch(blend_csp)
840 {
842 dt_develop_blendif_lab_make_mask(piece, (const float *const restrict)ivoid,
843 (const float *const restrict)ovoid, mask);
844 break;
846 dt_develop_blendif_rgb_hsl_make_mask(pipe, piece, (const float *const restrict)ivoid,
847 (const float *const restrict)ovoid, mask);
848 break;
850 dt_develop_blendif_rgb_jzczhz_make_mask(pipe, piece, (const float *const restrict)ivoid,
851 (const float *const restrict)ovoid, mask);
852 break;
854 dt_develop_blendif_raw_make_mask(piece, (const float *const restrict)ivoid,
855 (const float *const restrict)ovoid, mask);
856 break;
857 default:
858 break;
859 }
860
861 // post processing the mask
862 for(size_t index = 0; index < post_operations_size; ++index)
863 {
864 _develop_mask_post_processing operation = post_operations[index];
865 if(operation == DEVELOP_MASK_POST_FEATHER_IN)
866 {
867 const float guide_weight = dt_iop_colorspace_is_rgb(cst) ? 100.0f : 1.0f;
868 float *restrict guide = (float *restrict)ivoid;
869 if(!rois_equal)
870 guide = _develop_blend_process_copy_region(guide, ch * iwidth, ch * xoffs, ch * yoffs,
871 ch * owidth, ch * oheight);
872 if(!guide)
873 {
875 return 1;
876 }
877 if(_develop_blend_process_feather(guide, mask, owidth, oheight, ch, guide_weight,
878 d->feathering_radius, roi_out->scale) != 0)
879 {
880 if(!rois_equal)
883 return 1;
884 }
885 if(!rois_equal)
887 }
888 else if(operation == DEVELOP_MASK_POST_FEATHER_OUT)
889 {
890 const float guide_weight = dt_iop_colorspace_is_rgb(cst) ? 100.0f : 1.0f;
891 if(_develop_blend_process_feather((const float *const restrict)ovoid, mask, owidth, oheight, ch,
892 guide_weight, d->feathering_radius, roi_out->scale) != 0)
893 {
895 return 1;
896 }
897 }
898 else if(operation == DEVELOP_MASK_POST_BLUR)
899 {
900 const float sigma = d->blur_radius * roi_out->scale;
901 const float mmax[] = { 1.0f };
902 const float mmin[] = { 0.0f };
903
904 dt_gaussian_t *g = dt_gaussian_init(owidth, oheight, 1, mmax, mmin, sigma, 0);
905 if(g)
906 {
907 dt_gaussian_blur(g, mask, mask);
909 }
910 }
911 else if(operation == DEVELOP_MASK_POST_TONE_CURVE)
912 {
913 _develop_blend_process_mask_tone_curve(mask, buffsize, d->contrast, d->brightness, opacity);
914 }
915 }
916 }
917
918 // now apply blending with per-pixel opacity value as defined in mask
919 // select the blend operator
920 switch(blend_csp)
921 {
923 dt_develop_blendif_lab_blend(pipe, piece, (const float *const restrict)ivoid, (float *const restrict)ovoid,
924 mask, request_mask_display);
925 break;
927 dt_develop_blendif_rgb_hsl_blend(pipe, piece, (const float *const restrict)ivoid, (float *const restrict)ovoid,
928 mask, request_mask_display);
929 break;
931 dt_develop_blendif_rgb_jzczhz_blend(pipe, piece, (const float *const restrict)ivoid, (float *const restrict)ovoid,
932 mask, request_mask_display);
933 break;
935 dt_develop_blendif_raw_blend(pipe, piece, (const float *const restrict)ivoid, (float *const restrict)ovoid,
936 mask, request_mask_display);
937 break;
938 default:
939 break;
940 }
941
942 // register if _this_ module should expose mask or display channel
944 {
945 pipe->mask_display = request_mask_display;
946 }
947
948 // check if we should store the mask for export or use in subsequent modules
950 {
951 const uint64_t mask_hash = dt_dev_pixelpipe_raster_mask_hash(piece, 0);
952 dt_pixel_cache_entry_t *mask_entry = NULL;
953 void *cache_data = NULL;
954 const int created = dt_dev_pixelpipe_cache_get(
955 mask_hash, sizeof(float) * buffsize,
956 "raster mask", pipe->type, TRUE, &cache_data, &mask_entry);
957
958 if(IS_NULL_PTR(cache_data) || IS_NULL_PTR(mask_entry))
959 {
960 if(created && !IS_NULL_PTR(mask_entry))
962 if(!IS_NULL_PTR(mask_entry))
963 {
965 if(created)
967 }
969 return 1;
970 }
971
972 // Cache entries are immutable for a given provider state. Only the thread
973 // which created this dedicated key writes the mask; exact hits reuse it.
974 if(created)
975 {
976 memcpy(cache_data, _mask, sizeof(float) * buffsize);
978 }
979 // Transfer cache_get()'s reference to the pipe. It keeps this side-band
980 // output alive until the next graph state is prepared or the pipe closes.
981 g_array_append_val(pipe->raster_mask_hashes, mask_hash);
983
984 if(created && dt_supervisor_active())
986 dt_supervisor_node_key(pipe->type, piece->module->op,
987 piece->module->multi_priority),
988 piece->hash, piece->global_hash, piece->module->op,
989 piece->module->multi_priority, piece->module->iop_order,
990 pipe->type, pipe->imgid, piece->roi_out.width,
991 piece->roi_out.height, -1, sizeof(float) * buffsize,
992 "raster mask");
993
995 "[raster masks] %s mask id 0 for module %s (%s) for pipe %s"
996 " with cache hash %" PRIu64 "\n",
997 created ? "published" : "reused cached",
998 piece->module->op, piece->module->multi_name,
999 dt_pipe_type_to_str(pipe->type), mask_hash);
1000 }
1001 else
1002 {
1004 "[raster masks] discarding unpublished mask id 0 for module %s (%s) for pipe %s\n",
1005 piece->module->op, piece->module->multi_name,
1006 dt_pipe_type_to_str(pipe->type));
1008 }
1009 // raster error is the only one we catch
1010 return raster_error;
1011}
1012
1013#ifdef HAVE_OPENCL
1014static void _refine_with_detail_mask_cl(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe,
1015 const struct dt_dev_pixelpipe_iop_t *piece, float *mask,
1016 const float level, const int devid)
1017{
1018 const dt_iop_roi_t *const roi_out = &piece->roi_out;
1019 if(level == 0.0f) return;
1020 const gboolean info = (dt_get_debug_flags() & DT_DEBUG_MASKS);
1021
1022 const int detail = (level > 0.0f);
1023 const float threshold = _detail_mask_threshold(level, detail);
1024 float *lum = NULL;
1025 float *rawdetail_mask = NULL;
1026 cl_mem tmp = NULL;
1027 cl_mem blur = NULL;
1028 cl_mem out = NULL;
1029
1030 const dt_dev_pixelpipe_t *p = pipe;
1031 rawdetail_mask = dt_dev_retrieve_rawdetail_mask(pipe, self);
1032 if(IS_NULL_PTR(rawdetail_mask)) return;
1033
1034 const int iwidth = p->rawdetail_mask_roi.width;
1035 const int iheight = p->rawdetail_mask_roi.height;
1036 const int owidth = roi_out->width;
1037 const int oheight = roi_out->height;
1038 if(info) fprintf(stderr, "[_refine_with_detail_mask_cl] in module %s %ix%i --> %ix%i\n", self->op, iwidth, iheight, owidth, oheight);
1039
1040 lum = dt_pixelpipe_cache_alloc_align_float((size_t)iwidth * iheight, pipe);
1041 if(IS_NULL_PTR(lum)) goto error;
1042 tmp = dt_opencl_alloc_device(devid, iwidth, iheight, sizeof(float));
1043 if(IS_NULL_PTR(tmp)) goto error;
1044 out = dt_opencl_alloc_device_buffer(devid, sizeof(float) * iwidth * iheight);
1045 if(IS_NULL_PTR(out)) goto error;
1046 blur = dt_opencl_alloc_device_buffer(devid, sizeof(float) * iwidth * iheight);
1047 if(IS_NULL_PTR(blur)) goto error;
1048
1049 {
1050 const int err = dt_opencl_write_host_to_device(devid, rawdetail_mask, tmp, iwidth, iheight, sizeof(float));
1051 if(err != CL_SUCCESS) goto error;
1052 }
1053
1054 {
1055 size_t sizes[3] = { ROUNDUPDWD(iwidth, devid), ROUNDUPDHT(iheight, devid), 1 };
1057 dt_opencl_set_kernel_arg(devid, kernel, 0, sizeof(cl_mem), &out);
1058 dt_opencl_set_kernel_arg(devid, kernel, 1, sizeof(cl_mem), &tmp);
1059 dt_opencl_set_kernel_arg(devid, kernel, 2, sizeof(int), &iwidth);
1060 dt_opencl_set_kernel_arg(devid, kernel, 3, sizeof(int), &iheight);
1061 const int err = dt_opencl_enqueue_kernel_2d(devid, kernel, sizes);
1062 if(err != CL_SUCCESS) goto error;
1063 }
1064
1065 {
1066 size_t sizes[3] = { ROUNDUPDWD(iwidth, devid), ROUNDUPDHT(iheight, devid), 1 };
1068 dt_opencl_set_kernel_arg(devid, kernel, 0, sizeof(cl_mem), &out);
1069 dt_opencl_set_kernel_arg(devid, kernel, 1, sizeof(cl_mem), &blur);
1070 dt_opencl_set_kernel_arg(devid, kernel, 2, sizeof(int), &iwidth);
1071 dt_opencl_set_kernel_arg(devid, kernel, 3, sizeof(int), &iheight);
1072 dt_opencl_set_kernel_arg(devid, kernel, 4, sizeof(float), &threshold);
1073 dt_opencl_set_kernel_arg(devid, kernel, 5, sizeof(int), &detail);
1074 const int err = dt_opencl_enqueue_kernel_2d(devid, kernel, sizes);
1075 if(err != CL_SUCCESS) goto error;
1076 }
1077
1078 {
1079 float blurmat[13];
1080 dt_masks_blur_9x9_coeff(blurmat, 2.0f);
1081 cl_mem dev_blurmat = NULL;
1082 dev_blurmat = dt_opencl_copy_host_to_device_constant(devid, sizeof(float) * 13, blurmat);
1083 if(!IS_NULL_PTR(dev_blurmat))
1084 {
1085 size_t sizes[3] = { ROUNDUPDWD(iwidth, devid), ROUNDUPDHT(iheight, devid), 1 };
1086 const int clkernel = _blendop_cl_global->kernel_mask_blur;
1087 dt_opencl_set_kernel_arg(devid, clkernel, 0, sizeof(cl_mem), &blur);
1088 dt_opencl_set_kernel_arg(devid, clkernel, 1, sizeof(cl_mem), &out);
1089 dt_opencl_set_kernel_arg(devid, clkernel, 2, sizeof(int), &iwidth);
1090 dt_opencl_set_kernel_arg(devid, clkernel, 3, sizeof(int), &iheight);
1091 dt_opencl_set_kernel_arg(devid, clkernel, 4, sizeof(cl_mem), (void *) &dev_blurmat);
1092 const int err = dt_opencl_enqueue_kernel_2d(devid, clkernel, sizes);
1093 dt_opencl_release_mem_object(dev_blurmat);
1094 if(err != CL_SUCCESS) goto error;
1095 }
1096 else
1097 {
1098 dt_opencl_release_mem_object(dev_blurmat);
1099 goto error;
1100 }
1101 }
1102
1103 {
1104 size_t sizes[3] = { ROUNDUPDWD(iwidth, devid), ROUNDUPDHT(iheight, devid), 1 };
1106 dt_opencl_set_kernel_arg(devid, kernel, 0, sizeof(cl_mem), &out);
1107 dt_opencl_set_kernel_arg(devid, kernel, 1, sizeof(cl_mem), &tmp);
1108 dt_opencl_set_kernel_arg(devid, kernel, 2, sizeof(int), &iwidth);
1109 dt_opencl_set_kernel_arg(devid, kernel, 3, sizeof(int), &iheight);
1110 const int err = dt_opencl_enqueue_kernel_2d(devid, kernel, sizes);
1111 if(err != CL_SUCCESS) goto error;
1112 }
1113
1114 {
1115 const int err = dt_opencl_read_host_from_device(devid, lum, tmp, iwidth, iheight, sizeof(float));
1116 if(err != CL_SUCCESS) goto error;
1117 }
1118
1122 tmp = blur = out = NULL;
1123
1124 // here we have the slightly blurred full detail available
1125 float *warp_mask = dt_dev_distort_detail_mask(p, lum, self);
1126 if(IS_NULL_PTR(warp_mask)) goto error;
1127 // dt_dev_distort_detail_mask() may return `lum` unchanged when no geometric distortion is needed.
1128 const gboolean warp_mask_aliases_lum = (warp_mask == lum);
1129 if(!warp_mask_aliases_lum)
1130 {
1132 lum = NULL;
1133 }
1134
1135 const int msize = owidth * oheight;
1136 __OMP_PARALLEL_FOR_SIMD__(aligned(mask, warp_mask : 64))
1137 for(int idx = 0; idx < msize; idx++)
1138 {
1139 mask[idx] = mask[idx] * warp_mask[idx];
1140 }
1142 if(warp_mask_aliases_lum) lum = NULL;
1143 return;
1144
1145 error:
1146 dt_pipeline_message(_("detail mask CL blending problem"));
1151}
1152
1153static inline void _blend_process_cl_exchange(cl_mem *a, cl_mem *b)
1154{
1155 cl_mem tmp = *a;
1156 *a = *b;
1157 *b = tmp;
1158}
1159
1161 const struct dt_dev_pixelpipe_iop_t *piece, cl_mem dev_in, cl_mem dev_out)
1162{
1163 const dt_iop_roi_t *const roi_in = &piece->roi_in;
1164 const dt_iop_roi_t *const roi_out = &piece->roi_out;
1165 if(pipe->bypass_blendif && self->dev->gui_attached && (self == self->dev->gui_module)) return 0;
1166
1168 if(IS_NULL_PTR(d)) return 0;
1169
1170 gboolean top_enabled = FALSE;
1171 gboolean raster_used = FALSE;
1172 gboolean drawn_used = FALSE;
1173 gboolean parametric_used = FALSE;
1174 dt_develop_blend_get_mask_usage(self, d, &top_enabled, &raster_used, &drawn_used, &parametric_used);
1175 if(!top_enabled) return 0;
1176 const unsigned int mask_mode = d->mask_mode;
1177 // A mask preview request must also be honored when every sub-mask is neutral.
1178 // In that case no raster/drawn/parametric mask is "used", but the effective
1179 // blend mask is still the uniform opacity mask written into alpha below.
1180 const gboolean preview_mask_mode = top_enabled;
1181
1182 const int ch = piece->dsc_in.channels; // the number of channels in the buffer
1183 const int xoffs = roi_out->x - roi_in->x;
1184 const int yoffs = roi_out->y - roi_in->y;
1185 const int iwidth = roi_in->width;
1186 const int iheight = roi_in->height;
1187 const int owidth = roi_out->width;
1188 const int oheight = roi_out->height;
1189 const size_t buffsize = (size_t)owidth * oheight;
1190 const float iscale = roi_in->scale;
1191 const float oscale = roi_out->scale;
1192 const gboolean rois_equal = iwidth == owidth || iheight == oheight || xoffs == 0 || yoffs == 0;
1193
1194 // In most cases of blending-enabled modules input and output of the module have
1195 // the exact same dimensions. Only in very special cases we allow a module's input
1196 // to exceed its output. This is namely the case for the spot removal module where
1197 // the source of a patch might lie outside the roi of the output image. Therefore:
1198 // We can only handle blending if roi_out and roi_in have the same scale and
1199 // if roi_out fits into the area given by roi_in. xoffs and yoffs describe the relative
1200 // offset of the input image to the output image. */
1201 if(oscale != iscale || xoffs < 0 || yoffs < 0
1202 || ((xoffs > 0 || yoffs > 0) && (owidth + xoffs > iwidth || oheight + yoffs > iheight)))
1203 {
1204 dt_pipeline_message(_("skipped blending in module '%s': roi's do not match"), self->op);
1205 return 0;
1206 }
1207
1208 // only non-zero if mask_display was set by an _earlier_ module
1209 const dt_dev_pixelpipe_display_mask_t mask_display = pipe->mask_display;
1210
1211 // does user want us to display a specific channel?
1212 const dt_dev_pixelpipe_display_mask_t request_mask_display
1213 = (self->dev->gui_attached && (self == self->dev->gui_module) && (pipe == self->dev->pipe)
1214 && preview_mask_mode)
1215 ? self->request_mask_display
1217
1218 // get channel max values depending on colorspace
1219 const dt_develop_blend_colorspace_t blend_csp = d->blend_cst;
1221
1222 // obtaining the list of mask operations to perform
1223 _develop_mask_post_processing post_operations[3];
1224 const size_t post_operations_size = _develop_mask_get_post_operations(d, piece, post_operations);
1225
1226 // get the clipped opacity value 0 - 1
1227 const float opacity = fminf(fmaxf(d->opacity / 100.0f, 0.0f), 1.0f);
1228 const gboolean use_masks = raster_used || drawn_used || parametric_used;
1229 const gboolean raster_only = raster_used && !drawn_used && !parametric_used;
1230
1231 // allocate space for blend mask
1232 float *_mask = dt_pixelpipe_cache_alloc_align_float(buffsize, pipe);
1233 if(IS_NULL_PTR(_mask))
1234 {
1235 dt_pipeline_message(_("could not allocate buffer for blending"));
1236 return 1;
1237 }
1238 float *const mask = _mask;
1239
1240 // setup some kernels
1241 int kernel_mask;
1242 int kernel;
1243 switch(blend_csp)
1244 {
1248 break;
1249
1253 break;
1254
1258 break;
1259
1261 default:
1264 break;
1265 }
1266 int kernel_mask_tone_curve = _blendop_cl_global->kernel_blendop_mask_tone_curve;
1267 int kernel_set_mask = _blendop_cl_global->kernel_blendop_set_mask;
1268 int kernel_display_channel = _blendop_cl_global->kernel_blendop_display_channel;
1269
1270 const int devid = pipe->devid;
1271 const int offs[2] = { xoffs, yoffs };
1272 const size_t sizes[] = { ROUNDUPDWD(owidth, devid), ROUNDUPDHT(oheight, devid), 1 };
1273
1274 cl_int err = -999;
1275 cl_mem dev_blendif_params = NULL;
1276 cl_mem dev_boost_factors = NULL;
1277 cl_mem dev_mask_1 = NULL;
1278 cl_mem dev_mask_2 = NULL;
1279 cl_mem dev_tmp = NULL;
1280 cl_mem dev_guide = NULL;
1281
1282 cl_mem dev_profile_info = NULL;
1283 cl_mem dev_profile_lut = NULL;
1284 dt_colorspaces_iccprofile_info_cl_t *profile_info_cl = NULL;
1285 cl_float *profile_lut_cl = NULL;
1286
1287 cl_mem dev_work_profile_info = NULL;
1288 cl_mem dev_work_profile_lut = NULL;
1289 dt_colorspaces_iccprofile_info_cl_t *work_profile_info_cl = NULL;
1290 cl_float *work_profile_lut_cl = NULL;
1291
1292 size_t origin[] = { 0, 0, 0 };
1293 size_t region[] = { owidth, oheight, 1 };
1294
1295 // parameters, for every channel the 4 limits + pre-computed increasing slope and decreasing slope
1298
1299
1300 // copy blend parameters to constant device memory
1301 dev_blendif_params = dt_opencl_copy_host_to_device_constant(devid, sizeof(parameters), parameters);
1302 if(IS_NULL_PTR(dev_blendif_params)) goto error;
1303
1304 dev_mask_1 = dt_opencl_alloc_device(devid, owidth, oheight, sizeof(float));
1305 if(IS_NULL_PTR(dev_mask_1)) goto error;
1306
1308 const int use_profile = dt_develop_blendif_init_masking_profile(pipe, piece, &profile, blend_csp);
1309
1310 err = dt_ioppr_build_iccprofile_params_cl(use_profile ? &profile : NULL, devid, &profile_info_cl,
1311 &profile_lut_cl, &dev_profile_info, &dev_profile_lut);
1312 if(err != CL_SUCCESS) goto error;
1313
1314 if(!use_masks)
1315 {
1316 // blend uniformly (no drawn or parametric mask)
1317
1318 // set dev_mask with global opacity value
1319 dt_opencl_set_kernel_arg(devid, kernel_set_mask, 0, sizeof(cl_mem), (void *)&dev_mask_1);
1320 dt_opencl_set_kernel_arg(devid, kernel_set_mask, 1, sizeof(int), (void *)&owidth);
1321 dt_opencl_set_kernel_arg(devid, kernel_set_mask, 2, sizeof(int), (void *)&oheight);
1322 dt_opencl_set_kernel_arg(devid, kernel_set_mask, 3, sizeof(float), (void *)&opacity);
1323 err = dt_opencl_enqueue_kernel_2d(devid, kernel_set_mask, sizes);
1324 if(err != CL_SUCCESS) goto error;
1325 }
1326 else if(raster_only)
1327 {
1328 int raster_error = 0;
1329 _develop_blend_init_raster_mask(d, self, pipe, piece, mask, owidth, oheight, &raster_error);
1330 if(raster_error) goto error;
1331 dt_iop_image_mul_const(mask, opacity, owidth, oheight, 1);
1332
1333 err = dt_opencl_write_host_to_device(devid, mask, dev_mask_1, owidth, oheight, sizeof(float));
1334 if(err != CL_SUCCESS) goto error;
1335 }
1336 else
1337 {
1338 if(!raster_used && !drawn_used)
1339 {
1340 // Parametric-only blending has no raster/drawn form mask to seed `mask`.
1341 // The OpenCL mask kernel reads that form mask from `dev_mask_1`, so keep
1342 // the CPU staging buffer explicit and initialized before upload.
1343 const float fill = (d->mask_combine & DEVELOP_COMBINE_INCL) ? 0.0f : 1.0f;
1344 dt_iop_image_fill(mask, fill, owidth, oheight, 1);
1345 }
1346 else if(raster_used)
1347 {
1348 int raster_error = 0;
1349 _develop_blend_init_raster_mask(d, self, pipe, piece, mask, owidth, oheight, &raster_error);
1350 if(raster_error) goto error;
1351
1352 if(drawn_used)
1353 {
1354 float *const restrict drawn_mask = dt_pixelpipe_cache_alloc_align_float(buffsize, pipe);
1355 if(IS_NULL_PTR(drawn_mask)) goto error;
1356
1357 if(_develop_blend_init_drawn_mask(d, self, pipe, piece, roi_out, drawn_mask, owidth, oheight) != 0)
1358 {
1360 goto error;
1361 }
1362
1363 _develop_blend_combine_masks(mask, drawn_mask, buffsize);
1365 }
1366 }
1367 else if(drawn_used
1368 && _develop_blend_init_drawn_mask(d, self, pipe, piece, roi_out, mask, owidth, oheight) != 0)
1369 {
1370 goto error;
1371 }
1372 _refine_with_detail_mask_cl(self, pipe, piece, mask, d->details, devid);
1373
1374 // write mask from host to device
1375 dev_mask_2 = dt_opencl_alloc_device(devid, owidth, oheight, sizeof(float));
1376 if(IS_NULL_PTR(dev_mask_2)) goto error;
1377 err = dt_opencl_write_host_to_device(devid, mask, dev_mask_1, owidth, oheight, sizeof(float));
1378 if(err != CL_SUCCESS) goto error;
1379
1380 // get parametric mask (if any) and apply global opacity
1381 const unsigned blendif = d->blendif;
1382 const unsigned int mask_combine = d->mask_combine;
1383 dt_opencl_set_kernel_arg(devid, kernel_mask, 0, sizeof(cl_mem), (void *)&dev_in);
1384 dt_opencl_set_kernel_arg(devid, kernel_mask, 1, sizeof(cl_mem), (void *)&dev_out);
1385 dt_opencl_set_kernel_arg(devid, kernel_mask, 2, sizeof(cl_mem), (void *)&dev_mask_1);
1386 dt_opencl_set_kernel_arg(devid, kernel_mask, 3, sizeof(cl_mem), (void *)&dev_mask_2);
1387 dt_opencl_set_kernel_arg(devid, kernel_mask, 4, sizeof(int), (void *)&owidth);
1388 dt_opencl_set_kernel_arg(devid, kernel_mask, 5, sizeof(int), (void *)&oheight);
1389 dt_opencl_set_kernel_arg(devid, kernel_mask, 6, sizeof(float), (void *)&opacity);
1390 dt_opencl_set_kernel_arg(devid, kernel_mask, 7, sizeof(unsigned), (void *)&blendif);
1391 dt_opencl_set_kernel_arg(devid, kernel_mask, 8, sizeof(cl_mem), (void *)&dev_blendif_params);
1392 dt_opencl_set_kernel_arg(devid, kernel_mask, 9, sizeof(unsigned), (void *)&mask_mode);
1393 dt_opencl_set_kernel_arg(devid, kernel_mask, 10, sizeof(unsigned), (void *)&mask_combine);
1394 dt_opencl_set_kernel_arg(devid, kernel_mask, 11, 2 * sizeof(int), (void *)&offs);
1395 dt_opencl_set_kernel_arg(devid, kernel_mask, 12, sizeof(cl_mem), (void *)&dev_profile_info);
1396 dt_opencl_set_kernel_arg(devid, kernel_mask, 13, sizeof(cl_mem), (void *)&dev_profile_lut);
1397 dt_opencl_set_kernel_arg(devid, kernel_mask, 14, sizeof(int), (void *)&use_profile);
1398 err = dt_opencl_enqueue_kernel_2d(devid, kernel_mask, sizes);
1399 if(err != CL_SUCCESS)
1400 {
1401 fprintf(stderr, "[dt_develop_blend_process_cl] error %i enqueue kernel\n", err);
1402 goto error;
1403 }
1404
1405 // the mask is now located in dev_mask_2, put it in dev_mask_1
1406 _blend_process_cl_exchange(&dev_mask_1, &dev_mask_2);
1407
1408 // post processing the mask (it will always be stored in dev_mask_1)
1409 for(size_t index = 0; index < post_operations_size; ++index)
1410 {
1411 _develop_mask_post_processing operation = post_operations[index];
1412 if(operation == DEVELOP_MASK_POST_FEATHER_IN)
1413 {
1414 int w = (int)(2 * d->feathering_radius * roi_out->scale + 0.5f);
1415 if (w < 1) w = 1;
1416 const float sqrt_eps = 1.0f;
1417 const float guide_weight = dt_iop_colorspace_is_rgb(cst) ? 100.0f : 1.0f;
1418
1419 cl_mem guide = dev_in;
1420 if(!rois_equal)
1421 {
1422 dev_guide = dt_opencl_alloc_device(devid, owidth, oheight, sizeof(float) * ch);
1423 if(IS_NULL_PTR(dev_guide)) goto error;
1424 guide = dev_guide;
1425 size_t origin_1[] = { xoffs, yoffs, 0 };
1426 size_t origin_2[] = { 0, 0, 0 };
1427 err = dt_opencl_enqueue_copy_image(devid, dev_in, guide, origin_2, origin_1, region);
1428 if(err != CL_SUCCESS) goto error;
1429 }
1430 if(guided_filter_cl(devid, guide, dev_mask_1, dev_mask_2, owidth, oheight, ch, w, sqrt_eps, guide_weight,
1431 0.0f, 1.0f) != 0)
1432 goto error;
1433 if(!rois_equal)
1434 {
1436 dev_guide = NULL;
1437 }
1438 _blend_process_cl_exchange(&dev_mask_1, &dev_mask_2);
1439 }
1440 else if(operation == DEVELOP_MASK_POST_FEATHER_OUT)
1441 {
1442 int w = (int)(2 * d->feathering_radius * roi_out->scale + 0.5f);
1443 if (w < 1) w = 1;
1444 const float sqrt_eps = 1.0f;
1445 const float guide_weight = dt_iop_colorspace_is_rgb(cst) ? 100.0f : 1.0f;
1446
1447 if(guided_filter_cl(devid, dev_out, dev_mask_1, dev_mask_2, owidth, oheight, ch, w, sqrt_eps, guide_weight,
1448 0.0f, 1.0f) != 0)
1449 goto error;
1450 _blend_process_cl_exchange(&dev_mask_1, &dev_mask_2);
1451 }
1452 else if(operation == DEVELOP_MASK_POST_BLUR)
1453 {
1454 const float sigma = d->blur_radius * roi_out->scale;
1455 const float mmax[] = { 1.0f };
1456 const float mmin[] = { 0.0f };
1457
1458 dt_gaussian_cl_t *g = dt_gaussian_init_cl(devid, owidth, oheight, 1, mmax, mmin, sigma, 0);
1459 if(IS_NULL_PTR(g)) goto error;
1460 err = dt_gaussian_blur_cl(g, dev_mask_1, dev_mask_2);
1462 if(err != CL_SUCCESS) goto error;
1463 _blend_process_cl_exchange(&dev_mask_1, &dev_mask_2);
1464 }
1465 else if(operation == DEVELOP_MASK_POST_TONE_CURVE)
1466 {
1467 const float e = expf(3.f * d->contrast);
1468 const float brightness = d->brightness;
1469 dt_opencl_set_kernel_arg(devid, kernel_mask_tone_curve, 0, sizeof(cl_mem), (void *)&dev_mask_1);
1470 dt_opencl_set_kernel_arg(devid, kernel_mask_tone_curve, 1, sizeof(cl_mem), (void *)&dev_mask_2);
1471 dt_opencl_set_kernel_arg(devid, kernel_mask_tone_curve, 2, sizeof(int), (void *)&owidth);
1472 dt_opencl_set_kernel_arg(devid, kernel_mask_tone_curve, 3, sizeof(int), (void *)&oheight);
1473 dt_opencl_set_kernel_arg(devid, kernel_mask_tone_curve, 4, sizeof(float), (void *)&e);
1474 dt_opencl_set_kernel_arg(devid, kernel_mask_tone_curve, 5, sizeof(float), (void *)&brightness);
1475 dt_opencl_set_kernel_arg(devid, kernel_mask_tone_curve, 6, sizeof(float), (void *)&opacity);
1476 err = dt_opencl_enqueue_kernel_2d(devid, kernel_mask_tone_curve, sizes);
1477 if(err != CL_SUCCESS) goto error;
1478 _blend_process_cl_exchange(&dev_mask_1, &dev_mask_2);
1479 }
1480 }
1481
1482 // get rid of dev_mask_2
1483 dt_opencl_release_mem_object(dev_mask_2);
1484 dev_mask_2 = NULL;
1485 }
1486
1487 // get temporary buffer for output image to overcome readonly/writeonly limitation
1488 dev_tmp = dt_opencl_alloc_device(devid, owidth, oheight, sizeof(float) * ch);
1489 if(IS_NULL_PTR(dev_tmp)) goto error;
1490
1491 err = dt_opencl_enqueue_copy_image(devid, dev_out, dev_tmp, origin, origin, region);
1492 if(err != CL_SUCCESS) goto error;
1493
1494 if(request_mask_display & DT_DEV_PIXELPIPE_DISPLAY_ANY)
1495 {
1496 // load the boost factors in the device memory
1497 dev_boost_factors = dt_opencl_copy_host_to_device_constant(devid, sizeof(d->blendif_boost_factors),
1498 d->blendif_boost_factors);
1499 if(IS_NULL_PTR(dev_boost_factors)) goto error;
1500
1501 // the display channel of Lab blending is generated in RGB and should be transformed to Lab
1502 // the transformation in the pipeline is currently always using the work profile
1504 const int use_work_profile = !IS_NULL_PTR(work_profile);
1505
1506 err = dt_ioppr_build_iccprofile_params_cl(work_profile, devid, &work_profile_info_cl, &work_profile_lut_cl,
1507 &dev_work_profile_info, &dev_work_profile_lut);
1508 if(err != CL_SUCCESS) goto error;
1509
1510 // let us display a specific channel
1511 dt_opencl_set_kernel_arg(devid, kernel_display_channel, 0, sizeof(cl_mem), (void *)&dev_in);
1512 dt_opencl_set_kernel_arg(devid, kernel_display_channel, 1, sizeof(cl_mem), (void *)&dev_tmp);
1513 dt_opencl_set_kernel_arg(devid, kernel_display_channel, 2, sizeof(cl_mem), (void *)&dev_mask_1);
1514 dt_opencl_set_kernel_arg(devid, kernel_display_channel, 3, sizeof(cl_mem), (void *)&dev_out);
1515 dt_opencl_set_kernel_arg(devid, kernel_display_channel, 4, sizeof(int), (void *)&owidth);
1516 dt_opencl_set_kernel_arg(devid, kernel_display_channel, 5, sizeof(int), (void *)&oheight);
1517 dt_opencl_set_kernel_arg(devid, kernel_display_channel, 6, 2 * sizeof(int), (void *)&offs);
1518 dt_opencl_set_kernel_arg(devid, kernel_display_channel, 7, sizeof(int), (void *)&request_mask_display);
1519 dt_opencl_set_kernel_arg(devid, kernel_display_channel, 8, sizeof(cl_mem), (void*)&dev_boost_factors);
1520 dt_opencl_set_kernel_arg(devid, kernel_display_channel, 9, sizeof(cl_mem), (void *)&dev_profile_info);
1521 dt_opencl_set_kernel_arg(devid, kernel_display_channel, 10, sizeof(cl_mem), (void *)&dev_profile_lut);
1522 dt_opencl_set_kernel_arg(devid, kernel_display_channel, 11, sizeof(int), (void *)&use_profile);
1523 dt_opencl_set_kernel_arg(devid, kernel_display_channel, 12, sizeof(cl_mem), (void *)&dev_work_profile_info);
1524 dt_opencl_set_kernel_arg(devid, kernel_display_channel, 13, sizeof(cl_mem), (void *)&dev_work_profile_lut);
1525 dt_opencl_set_kernel_arg(devid, kernel_display_channel, 14, sizeof(int), (void *)&use_work_profile);
1526 err = dt_opencl_enqueue_kernel_2d(devid, kernel_display_channel, sizes);
1527 if(err != CL_SUCCESS)
1528 {
1529 fprintf(stderr, "[dt_develop_blend_process_cl] error %i enqueue kernel\n", err);
1530 goto error;
1531 }
1532 }
1533 else
1534 {
1535 // apply blending with per-pixel opacity value as defined in dev_mask_1
1536 const unsigned int blend_mode = d->blend_mode;
1537 const float blend_parameter = exp2f(d->blend_parameter);
1538 dt_opencl_set_kernel_arg(devid, kernel, 0, sizeof(cl_mem), (void *)&dev_in);
1539 dt_opencl_set_kernel_arg(devid, kernel, 1, sizeof(cl_mem), (void *)&dev_tmp);
1540 dt_opencl_set_kernel_arg(devid, kernel, 2, sizeof(cl_mem), (void *)&dev_mask_1);
1541 dt_opencl_set_kernel_arg(devid, kernel, 3, sizeof(cl_mem), (void *)&dev_out);
1542 dt_opencl_set_kernel_arg(devid, kernel, 4, sizeof(int), (void *)&owidth);
1543 dt_opencl_set_kernel_arg(devid, kernel, 5, sizeof(int), (void *)&oheight);
1544 dt_opencl_set_kernel_arg(devid, kernel, 6, sizeof(unsigned), (void *)&blend_mode);
1545 dt_opencl_set_kernel_arg(devid, kernel, 7, sizeof(float), (void *)&blend_parameter);
1546 dt_opencl_set_kernel_arg(devid, kernel, 8, 2 * sizeof(int), (void *)&offs);
1547 dt_opencl_set_kernel_arg(devid, kernel, 9, sizeof(int), (void *)&mask_display);
1548 err = dt_opencl_enqueue_kernel_2d(devid, kernel, sizes);
1549 if(err != CL_SUCCESS) goto error;
1550 }
1551
1552 // register if _this_ module should expose mask or display channel
1554 {
1555 pipe->mask_display = request_mask_display;
1556 }
1557
1558
1559 // check if we should store the mask for export or use in subsequent modules
1561 {
1562 // get back final mask from the device to store it for later use
1563 if(!raster_only)
1564 {
1565 err = dt_opencl_copy_device_to_host(devid, mask, dev_mask_1, owidth, oheight, sizeof(float));
1566 if(err != CL_SUCCESS) goto error;
1567 }
1568
1569 const uint64_t mask_hash = dt_dev_pixelpipe_raster_mask_hash(piece, 0);
1570 dt_pixel_cache_entry_t *mask_entry = NULL;
1571 void *cache_data = NULL;
1572 const int created = dt_dev_pixelpipe_cache_get(
1573 mask_hash, sizeof(float) * buffsize,
1574 "raster mask", pipe->type, TRUE, &cache_data, &mask_entry);
1575
1576 if(IS_NULL_PTR(cache_data) || IS_NULL_PTR(mask_entry))
1577 {
1578 if(created && !IS_NULL_PTR(mask_entry))
1580 if(!IS_NULL_PTR(mask_entry))
1581 {
1583 if(created)
1585 }
1586 goto error;
1587 }
1588
1589 // The OpenCL mask has been materialized into `_mask` above. Publish that
1590 // host payload once so CPU and GPU consumers share the same cache entry.
1591 if(created)
1592 {
1593 memcpy(cache_data, _mask, sizeof(float) * buffsize);
1595 }
1596 // Transfer cache_get()'s reference to the pipe. It keeps this side-band
1597 // output alive until the next graph state is prepared or the pipe closes.
1598 g_array_append_val(pipe->raster_mask_hashes, mask_hash);
1600 _mask = NULL;
1601
1602 if(created && dt_supervisor_active())
1604 dt_supervisor_node_key(pipe->type, piece->module->op,
1605 piece->module->multi_priority),
1606 piece->hash, piece->global_hash, piece->module->op,
1607 piece->module->multi_priority, piece->module->iop_order,
1608 pipe->type, pipe->imgid, piece->roi_out.width,
1609 piece->roi_out.height, devid, sizeof(float) * buffsize,
1610 "raster mask");
1611
1613 "[raster masks] %s mask id 0 for module %s (%s) for pipe %s"
1614 " with cache hash %" PRIu64 "\n",
1615 created ? "published" : "reused cached",
1616 piece->module->op, piece->module->multi_name,
1617 dt_pipe_type_to_str(pipe->type), mask_hash);
1618 }
1619 else
1620 {
1622 "[raster masks] discarding unpublished mask id 0 for module %s (%s) for pipe %s\n",
1623 piece->module->op, piece->module->multi_name,
1624 dt_pipe_type_to_str(pipe->type));
1626 }
1627
1628 dt_opencl_release_mem_object(dev_blendif_params);
1629 dt_opencl_release_mem_object(dev_boost_factors);
1630 dt_opencl_release_mem_object(dev_mask_1);
1632 dt_ioppr_free_iccprofile_params_cl(&profile_info_cl, &profile_lut_cl, &dev_profile_info, &dev_profile_lut);
1633 dt_ioppr_free_iccprofile_params_cl(&work_profile_info_cl, &work_profile_lut_cl, &dev_work_profile_info,
1634 &dev_work_profile_lut);
1635 return 0;
1636
1637error:
1639 dt_opencl_release_mem_object(dev_blendif_params);
1640 dt_opencl_release_mem_object(dev_boost_factors);
1641 dt_opencl_release_mem_object(dev_mask_1);
1642 dt_opencl_release_mem_object(dev_mask_2);
1645 if(profile_info_cl) dt_ioppr_free_iccprofile_params_cl(&profile_info_cl, &profile_lut_cl, &dev_profile_info, &dev_profile_lut);
1646 if(work_profile_info_cl) dt_ioppr_free_iccprofile_params_cl(&work_profile_info_cl, &work_profile_lut_cl, &dev_work_profile_info,
1647 &dev_work_profile_lut);
1648 dt_print(DT_DEBUG_OPENCL, "[opencl_blendop] couldn't enqueue kernel! %d\n", err);
1649 return 1;
1650}
1651#endif
1652
1655{
1656#ifdef HAVE_OPENCL
1658
1659 const int program = 3; // blendop.cl, from programs.conf
1660 b->kernel_blendop_mask_Lab = dt_opencl_create_kernel(program, "blendop_mask_Lab");
1661 b->kernel_blendop_mask_RAW = dt_opencl_create_kernel(program, "blendop_mask_RAW");
1662 b->kernel_blendop_mask_rgb_hsl = dt_opencl_create_kernel(program, "blendop_mask_rgb_hsl");
1663 b->kernel_blendop_mask_rgb_jzczhz = dt_opencl_create_kernel(program, "blendop_mask_rgb_jzczhz");
1664 b->kernel_blendop_Lab = dt_opencl_create_kernel(program, "blendop_Lab");
1665 b->kernel_blendop_RAW = dt_opencl_create_kernel(program, "blendop_RAW");
1666 b->kernel_blendop_rgb_hsl = dt_opencl_create_kernel(program, "blendop_rgb_hsl");
1667 b->kernel_blendop_rgb_jzczhz = dt_opencl_create_kernel(program, "blendop_rgb_jzczhz");
1668 b->kernel_blendop_mask_tone_curve = dt_opencl_create_kernel(program, "blendop_mask_tone_curve");
1669 b->kernel_blendop_set_mask = dt_opencl_create_kernel(program, "blendop_set_mask");
1670 b->kernel_blendop_display_channel = dt_opencl_create_kernel(program, "blendop_display_channel");
1671
1672 const int program_rcd = 31;
1673 b->kernel_calc_Y0_mask = dt_opencl_create_kernel(program_rcd, "calc_Y0_mask");
1674 b->kernel_calc_scharr_mask = dt_opencl_create_kernel(program_rcd, "calc_scharr_mask");
1675 b->kernel_write_mask = dt_opencl_create_kernel(program_rcd, "writeout_mask");
1676 b->kernel_read_mask = dt_opencl_create_kernel(program_rcd, "readin_mask");
1677 b->kernel_calc_blend = dt_opencl_create_kernel(program_rcd, "calc_detail_blend");
1678 b->kernel_mask_blur = dt_opencl_create_kernel(program_rcd, "fastblur_mask_9x9");
1679
1681#endif
1682}
1683
1686{
1687#ifdef HAVE_OPENCL
1689 _blendop_cl_global = NULL;
1690 if(IS_NULL_PTR(b)) return;
1691
1692 dt_opencl_free_kernel(b->kernel_blendop_mask_Lab);
1693 dt_opencl_free_kernel(b->kernel_blendop_mask_RAW);
1694 dt_opencl_free_kernel(b->kernel_blendop_mask_rgb_hsl);
1695 dt_opencl_free_kernel(b->kernel_blendop_mask_rgb_jzczhz);
1696 dt_opencl_free_kernel(b->kernel_blendop_Lab);
1697 dt_opencl_free_kernel(b->kernel_blendop_RAW);
1698 dt_opencl_free_kernel(b->kernel_blendop_rgb_hsl);
1699 dt_opencl_free_kernel(b->kernel_blendop_rgb_jzczhz);
1700 dt_opencl_free_kernel(b->kernel_blendop_mask_tone_curve);
1701 dt_opencl_free_kernel(b->kernel_blendop_set_mask);
1702 dt_opencl_free_kernel(b->kernel_blendop_display_channel);
1703 dt_opencl_free_kernel(b->kernel_calc_Y0_mask);
1704 dt_opencl_free_kernel(b->kernel_calc_scharr_mask);
1705 dt_opencl_free_kernel(b->kernel_write_mask);
1706 dt_opencl_free_kernel(b->kernel_read_mask);
1707 dt_opencl_free_kernel(b->kernel_calc_blend);
1708 dt_opencl_free_kernel(b->kernel_mask_blur);
1709 dt_free(b);
1710#endif
1711}
1712
1715{
1716 return DEVELOP_BLEND_VERSION;
1717}
1718
1720void tiling_callback_blendop(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe,
1721 const struct dt_dev_pixelpipe_iop_t *piece, struct dt_develop_tiling_t *tiling)
1722{
1723 tiling->factor = 3.5f; // in + out + (guide, tmp) + two quarter buffers for the mask
1724 tiling->maxbuf = 1.0f;
1725 tiling->overhead = 0;
1726 tiling->overlap = 0;
1727 tiling->xalign = 1;
1728 tiling->yalign = 1;
1729
1731 if(!IS_NULL_PTR(bldata))
1732 {
1733 if(bldata->details != 0.0f)
1734 tiling->factor += 0.75f; // details mask requires 3 additional quarter buffers
1735 }
1736}
1737
1741gboolean dt_develop_blend_params_is_all_zero(const void *params, size_t length)
1742{
1743 const char *data = (const char *)params;
1744
1745 for(size_t k = 0; k < length; k++)
1746 if(data[k]) return FALSE;
1747
1748 return TRUE;
1749}
1750
1751static uint32_t _blend_legacy_blend_mode(uint32_t legacy_blend_mode)
1752{
1753 uint32_t blend_mode = legacy_blend_mode & DEVELOP_BLEND_MODE_MASK;
1754 gboolean blend_reverse = FALSE;
1755 switch(blend_mode) {
1757 blend_mode = DEVELOP_BLEND_BOUNDED;
1758 break;
1760 blend_mode = DEVELOP_BLEND_BOUNDED;
1761 blend_reverse = TRUE;
1762 break;
1765 blend_mode = DEVELOP_BLEND_NORMAL2;
1766 break;
1768 blend_mode = DEVELOP_BLEND_MULTIPLY;
1769 blend_reverse = TRUE;
1770 break;
1771 default:
1772 break;
1773 }
1774 return (blend_reverse ? DEVELOP_BLEND_REVERSE : 0) | blend_mode;
1775}
1776
1778int dt_develop_blend_legacy_params(dt_iop_module_t *module, const void *const old_params,
1779 const int old_version, void *new_params, const int new_version,
1780 const int length)
1781{
1782 // edits before version 10 default to a display referred workflow
1784
1785 dt_develop_blend_params_t default_display_blend_params;
1786 dt_develop_blend_init_blend_parameters(&default_display_blend_params, cst);
1787
1788 // first deal with all-zero parameter sets, regardless of version number.
1789 // these occurred in previous darktable versions when modules without blend support stored zero-initialized data
1790 // in history stack. that's no problem unless the module gets blend support later (e.g. module exposure).
1791 // remedy: we simply initialize with the current default blend params in this case.
1792 if(dt_develop_blend_params_is_all_zero(old_params, length))
1793 {
1795
1796 *n = default_display_blend_params;
1797 return 0;
1798 }
1799
1800 if(old_version == 1 && new_version == 11)
1801 {
1803 typedef struct dt_develop_blend_params1_t
1804 {
1805 uint32_t mode;
1806 float opacity;
1807 uint32_t mask_id;
1808 } dt_develop_blend_params1_t;
1809
1810 if(length != sizeof(dt_develop_blend_params1_t)) return 1;
1811
1812 dt_develop_blend_params1_t *o = (dt_develop_blend_params1_t *)old_params;
1814
1815 *n = default_display_blend_params; // start with a fresh copy of default parameters
1817 n->blend_mode = _blend_legacy_blend_mode(o->mode);
1818 n->opacity = o->opacity;
1819 n->mask_id = o->mask_id;
1820 return 0;
1821 }
1822
1823 if(old_version == 2 && new_version == 11)
1824 {
1826 typedef struct dt_develop_blend_params2_t
1827 {
1829 uint32_t mode;
1831 float opacity;
1833 uint32_t mask_id;
1835 uint32_t blendif;
1837 float blendif_parameters[4 * 8];
1838 } dt_develop_blend_params2_t;
1839
1840 if(length != sizeof(dt_develop_blend_params2_t)) return 1;
1841
1842 dt_develop_blend_params2_t *o = (dt_develop_blend_params2_t *)old_params;
1844
1845 *n = default_display_blend_params; // start with a fresh copy of default parameters
1847 n->mask_mode |= ((o->blendif & (1u << DEVELOP_BLENDIF_active)) && (n->mask_mode == DEVELOP_MASK_ENABLED))
1849 : 0;
1850 n->blend_mode = _blend_legacy_blend_mode(o->mode);
1851 n->opacity = o->opacity;
1852 n->mask_id = o->mask_id;
1853 n->blendif = o->blendif & 0xff; // only just in case: knock out all bits
1854 // which were undefined in version
1855 // 2; also switch off old "active" bit
1856 for(int i = 0; i < (4 * 8); i++) n->blendif_parameters[i] = o->blendif_parameters[i];
1857
1858 return 0;
1859 }
1860
1861 if(old_version == 3 && new_version == 11)
1862 {
1864 typedef struct dt_develop_blend_params3_t
1865 {
1867 uint32_t mode;
1869 float opacity;
1871 uint32_t mask_id;
1873 uint32_t blendif;
1875 float blendif_parameters[4 * DEVELOP_BLENDIF_SIZE];
1876 } dt_develop_blend_params3_t;
1877
1878 if(length != sizeof(dt_develop_blend_params3_t)) return 1;
1879
1880 dt_develop_blend_params3_t *o = (dt_develop_blend_params3_t *)old_params;
1882
1883 *n = default_display_blend_params; // start with a fresh copy of default parameters
1885 n->mask_mode |= ((o->blendif & (1u << DEVELOP_BLENDIF_active)) && (n->mask_mode == DEVELOP_MASK_ENABLED))
1887 : 0;
1888 n->blend_mode = _blend_legacy_blend_mode(o->mode);
1889 n->opacity = o->opacity;
1890 n->mask_id = o->mask_id;
1891 n->blendif = o->blendif & ~(1u << DEVELOP_BLENDIF_active); // knock out old unused "active" flag
1892 memcpy(n->blendif_parameters, o->blendif_parameters, sizeof(float) * 4 * DEVELOP_BLENDIF_SIZE);
1893
1894 return 0;
1895 }
1896
1897 if(old_version == 4 && new_version == 11)
1898 {
1900 typedef struct dt_develop_blend_params4_t
1901 {
1903 uint32_t mode;
1905 float opacity;
1907 uint32_t mask_id;
1909 uint32_t blendif;
1911 float radius;
1913 float blendif_parameters[4 * DEVELOP_BLENDIF_SIZE];
1914 } dt_develop_blend_params4_t;
1915
1916 if(length != sizeof(dt_develop_blend_params4_t)) return 1;
1917
1918 dt_develop_blend_params4_t *o = (dt_develop_blend_params4_t *)old_params;
1920
1921 *n = default_display_blend_params; // start with a fresh copy of default parameters
1923 n->mask_mode |= ((o->blendif & (1u << DEVELOP_BLENDIF_active)) && (n->mask_mode == DEVELOP_MASK_ENABLED))
1925 : 0;
1926 n->blend_mode = _blend_legacy_blend_mode(o->mode);
1927 n->opacity = o->opacity;
1928 n->mask_id = o->mask_id;
1929 n->blur_radius = o->radius;
1930 n->blendif = o->blendif & ~(1u << DEVELOP_BLENDIF_active); // knock out old unused "active" flag
1931 memcpy(n->blendif_parameters, o->blendif_parameters, sizeof(float) * 4 * DEVELOP_BLENDIF_SIZE);
1932
1933 return 0;
1934 }
1935
1936 if(old_version == 5 && new_version == 11)
1937 {
1939 typedef struct dt_develop_blend_params5_t
1940 {
1942 uint32_t mask_mode;
1944 uint32_t blend_mode;
1946 float opacity;
1948 uint32_t mask_combine;
1950 uint32_t mask_id;
1952 uint32_t blendif;
1954 float radius;
1956 uint32_t reserved[4];
1958 float blendif_parameters[4 * DEVELOP_BLENDIF_SIZE];
1959 } dt_develop_blend_params5_t;
1960
1961 if(length != sizeof(dt_develop_blend_params5_t)) return 1;
1962
1963 dt_develop_blend_params5_t *o = (dt_develop_blend_params5_t *)old_params;
1965
1966 *n = default_display_blend_params; // start with a fresh copy of default parameters
1967 n->mask_mode = o->mask_mode;
1968 n->blend_mode = _blend_legacy_blend_mode(o->blend_mode);
1969 n->opacity = o->opacity;
1970 n->mask_combine = o->mask_combine;
1971 n->mask_id = o->mask_id;
1972 n->blur_radius = o->radius;
1973 // this is needed as version 5 contained a bug which screwed up history
1974 // stacks of even older
1975 // versions. potentially bad history stacks can be identified by an active
1976 // bit no. 32 in blendif.
1977 n->blendif = (o->blendif & (1u << DEVELOP_BLENDIF_active) ? o->blendif | 31 : o->blendif)
1978 & ~(1u << DEVELOP_BLENDIF_active);
1979 memcpy(n->blendif_parameters, o->blendif_parameters, sizeof(float) * 4 * DEVELOP_BLENDIF_SIZE);
1980
1981 return 0;
1982 }
1983
1984 if(old_version == 6 && new_version == 11)
1985 {
1987 typedef struct dt_develop_blend_params6_t
1988 {
1990 uint32_t mask_mode;
1992 uint32_t blend_mode;
1994 float opacity;
1996 uint32_t mask_combine;
1998 uint32_t mask_id;
2000 uint32_t blendif;
2002 float radius;
2004 uint32_t reserved[4];
2006 float blendif_parameters[4 * DEVELOP_BLENDIF_SIZE];
2007 } dt_develop_blend_params6_t;
2008
2009 if(length != sizeof(dt_develop_blend_params6_t)) return 1;
2010
2011 dt_develop_blend_params6_t *o = (dt_develop_blend_params6_t *)old_params;
2013
2014 *n = default_display_blend_params; // start with a fresh copy of default parameters
2015 n->mask_mode = o->mask_mode;
2016 n->blend_mode = _blend_legacy_blend_mode(o->blend_mode);
2017 n->opacity = o->opacity;
2018 n->mask_combine = o->mask_combine;
2019 n->mask_id = o->mask_id;
2020 n->blur_radius = o->radius;
2021 n->blendif = o->blendif;
2022 memcpy(n->blendif_parameters, o->blendif_parameters, sizeof(float) * 4 * DEVELOP_BLENDIF_SIZE);
2023 return 0;
2024 }
2025
2026 if(old_version == 7 && new_version == 11)
2027 {
2029 typedef struct dt_develop_blend_params7_t
2030 {
2032 uint32_t mask_mode;
2034 uint32_t blend_mode;
2036 float opacity;
2038 uint32_t mask_combine;
2040 uint32_t mask_id;
2042 uint32_t blendif;
2044 float radius;
2046 uint32_t reserved[4];
2048 float blendif_parameters[4 * DEVELOP_BLENDIF_SIZE];
2049 } dt_develop_blend_params7_t;
2050
2051 if(length != sizeof(dt_develop_blend_params7_t)) return 1;
2052
2053 dt_develop_blend_params7_t *o = (dt_develop_blend_params7_t *)old_params;
2055
2056 *n = default_display_blend_params; // start with a fresh copy of default parameters
2057 n->mask_mode = o->mask_mode;
2058 n->blend_mode = _blend_legacy_blend_mode(o->blend_mode);
2059 n->opacity = o->opacity;
2060 n->mask_combine = o->mask_combine;
2061 n->mask_id = o->mask_id;
2062 n->blur_radius = o->radius;
2063 n->blendif = o->blendif;
2064 memcpy(n->blendif_parameters, o->blendif_parameters, sizeof(float) * 4 * DEVELOP_BLENDIF_SIZE);
2065 return 0;
2066 }
2067
2068 if(old_version == 8 && new_version == 11)
2069 {
2071 typedef struct dt_develop_blend_params8_t
2072 {
2074 uint32_t mask_mode;
2076 uint32_t blend_mode;
2078 float opacity;
2080 uint32_t mask_combine;
2082 uint32_t mask_id;
2084 uint32_t blendif;
2086 float feathering_radius;
2088 uint32_t feathering_guide;
2090 float blur_radius;
2092 float contrast;
2094 float brightness;
2096 uint32_t reserved[4];
2098 float blendif_parameters[4 * DEVELOP_BLENDIF_SIZE];
2099 } dt_develop_blend_params8_t;
2100
2101 if(length != sizeof(dt_develop_blend_params8_t)) return 1;
2102
2103 dt_develop_blend_params8_t *o = (dt_develop_blend_params8_t *)old_params;
2105
2106 *n = default_display_blend_params; // start with a fresh copy of default parameters
2107 n->mask_mode = o->mask_mode;
2108 n->blend_mode = _blend_legacy_blend_mode(o->blend_mode);
2109 n->opacity = o->opacity;
2110 n->mask_combine = o->mask_combine;
2111 n->mask_id = o->mask_id;
2112 n->blendif = o->blendif;
2113 n->feathering_radius = o->feathering_radius;
2114 n->feathering_guide = o->feathering_guide;
2115 n->blur_radius = o->blur_radius;
2116 n->contrast = o->contrast;
2117 n->brightness = o->brightness;
2118 memcpy(n->blendif_parameters, o->blendif_parameters, sizeof(float) * 4 * DEVELOP_BLENDIF_SIZE);
2119 return 0;
2120 }
2121
2122 if(old_version == 9 && new_version == 11)
2123 {
2125 typedef struct dt_develop_blend_params9_t
2126 {
2129 uint32_t mask_mode;
2131 uint32_t blend_mode;
2133 float opacity;
2135 uint32_t mask_combine;
2137 uint32_t mask_id;
2139 uint32_t blendif;
2141 float feathering_radius;
2143 uint32_t feathering_guide;
2145 float blur_radius;
2147 float contrast;
2149 float brightness;
2151 uint32_t reserved[4];
2153 float blendif_parameters[4 * DEVELOP_BLENDIF_SIZE];
2154 dt_dev_operation_t raster_mask_source;
2155 int raster_mask_instance;
2156 int raster_mask_id;
2157 gboolean raster_mask_invert;
2158 } dt_develop_blend_params9_t;
2159
2160 if(length != sizeof(dt_develop_blend_params9_t)) return 1;
2161
2162 dt_develop_blend_params9_t *o = (dt_develop_blend_params9_t *)old_params;
2164
2165 *n = default_display_blend_params; // start with a fresh copy of default parameters
2166 n->mask_mode = o->mask_mode;
2167 n->blend_mode = _blend_legacy_blend_mode(o->blend_mode);
2168 n->opacity = o->opacity;
2169 n->mask_combine = o->mask_combine;
2170 n->mask_id = o->mask_id;
2171 n->blendif = o->blendif;
2172 n->feathering_radius = o->feathering_radius;
2173 n->feathering_guide = o->feathering_guide;
2174 n->blur_radius = o->blur_radius;
2175 n->contrast = o->contrast;
2176 n->brightness = o->brightness;
2177 memcpy(n->blendif_parameters, o->blendif_parameters, sizeof(float) * 4 * DEVELOP_BLENDIF_SIZE);
2178 memcpy(n->raster_mask_source, o->raster_mask_source, sizeof(n->raster_mask_source));
2179 n->raster_mask_instance = o->raster_mask_instance;
2180 n->raster_mask_id = o->raster_mask_id;
2181 n->raster_mask_invert = o->raster_mask_invert;
2182 return 0;
2183 }
2184
2185 if(old_version == 10 && new_version == 11)
2186 {
2188 typedef struct dt_develop_blend_params10_t
2189 {
2192 uint32_t mask_mode;
2194 int32_t blend_cst;
2196 uint32_t blend_mode;
2198 float blend_parameter;
2200 float opacity;
2202 uint32_t mask_combine;
2204 uint32_t mask_id;
2206 uint32_t blendif;
2208 float feathering_radius;
2210 uint32_t feathering_guide;
2212 float blur_radius;
2214 float contrast;
2216 float brightness;
2218 uint32_t reserved[4];
2220 float blendif_parameters[4 * DEVELOP_BLENDIF_SIZE];
2221 float blendif_boost_factors[DEVELOP_BLENDIF_SIZE];
2222 dt_dev_operation_t raster_mask_source;
2223 int raster_mask_instance;
2224 int raster_mask_id;
2225 gboolean raster_mask_invert;
2226 } dt_develop_blend_params10_t;
2227
2228 if(length != sizeof(dt_develop_blend_params10_t)) return 1;
2229
2230 dt_develop_blend_params10_t *o = (dt_develop_blend_params10_t *)old_params;
2232
2233 *n = default_display_blend_params; // start with a fresh copy of default parameters
2234 n->mask_mode = o->mask_mode;
2235 n->blend_cst = o->blend_cst;
2236 n->blend_mode = _blend_legacy_blend_mode(o->blend_mode);
2237 n->blend_parameter = o->blend_parameter;
2238 n->opacity = o->opacity;
2239 n->mask_combine = o->mask_combine;
2240 n->mask_id = o->mask_id;
2241 n->blendif = o->blendif;
2242 n->feathering_radius = o->feathering_radius;
2243 n->feathering_guide = o->feathering_guide;
2244 n->blur_radius = o->blur_radius;
2245 n->contrast = o->contrast;
2246 n->brightness = o->brightness;
2247 // fix intermediate devel versions for details mask and initialize n->details to proper values if something was wrong
2248 memcpy(&n->details, &o->reserved, sizeof(float));
2249 if(isnan(n->details)) n->details = 0.0f;
2250 n->details = fminf(1.0f, fmaxf(-1.0f, n->details));
2251
2252 memcpy(n->blendif_parameters, o->blendif_parameters, sizeof(float) * 4 * DEVELOP_BLENDIF_SIZE);
2253 memcpy(n->blendif_boost_factors, o->blendif_boost_factors, sizeof(float) * DEVELOP_BLENDIF_SIZE);
2254 memcpy(n->raster_mask_source, o->raster_mask_source, sizeof(n->raster_mask_source));
2255 n->raster_mask_instance = o->raster_mask_instance;
2256 n->raster_mask_id = o->raster_mask_id;
2257 n->raster_mask_invert = o->raster_mask_invert;
2258 return 0;
2259 }
2260
2261 return 1;
2262}
2263
2264int dt_develop_blend_legacy_params_from_so(dt_iop_module_so_t *module_so, const void *const old_params,
2265 const int old_version, void *new_params, const int new_version,
2266 const int length)
2267{
2268 // we need a dt_iop_module_t for dt_develop_blend_legacy_params()
2269 dt_iop_module_t *module = (dt_iop_module_t *)calloc(1, sizeof(dt_iop_module_t));
2270 if(dt_iop_load_module_by_so(module, module_so, NULL))
2271 {
2272 dt_free(module);
2273 return 1;
2274 }
2275
2276 if(module->params_size == 0)
2277 {
2278 dt_iop_cleanup_module(module);
2279 dt_free(module);
2280 return 1;
2281 }
2282
2283 // convert the old blend params to new
2284 const int res = dt_develop_blend_legacy_params(module, old_params, old_version,
2285 new_params, dt_develop_blend_version(),
2286 length);
2287 dt_iop_cleanup_module(module);
2288 dt_free(module);
2289 return res;
2290}
2291
2292// tools/update_modelines.sh
2293// remove-trailing-space on;
2294/* Name tables for the persisted blend enums. Defined here rather than in blend_gui.c:
2295 * they map params values to translatable names, and backend consumers
2296 * (develop/supervisor.c) read them with no GUI loaded. */
2298 = { { NC_("blendmode", "normal"), DEVELOP_BLEND_NORMAL2 },
2299 { NC_("blendmode", "normal bounded"), DEVELOP_BLEND_BOUNDED },
2300 { NC_("blendmode", "lighten"), DEVELOP_BLEND_LIGHTEN },
2301 { NC_("blendmode", "darken"), DEVELOP_BLEND_DARKEN },
2302 { NC_("blendmode", "multiply"), DEVELOP_BLEND_MULTIPLY },
2303 { NC_("blendmode", "average"), DEVELOP_BLEND_AVERAGE },
2304 { NC_("blendmode", "addition"), DEVELOP_BLEND_ADD },
2305 { NC_("blendmode", "subtract"), DEVELOP_BLEND_SUBTRACT },
2306 { NC_("blendmode", "difference"), DEVELOP_BLEND_DIFFERENCE2 },
2307 { NC_("blendmode", "screen"), DEVELOP_BLEND_SCREEN },
2308 { NC_("blendmode", "overlay"), DEVELOP_BLEND_OVERLAY },
2309 { NC_("blendmode", "softlight"), DEVELOP_BLEND_SOFTLIGHT },
2310 { NC_("blendmode", "hardlight"), DEVELOP_BLEND_HARDLIGHT },
2311 { NC_("blendmode", "vividlight"), DEVELOP_BLEND_VIVIDLIGHT },
2312 { NC_("blendmode", "linearlight"), DEVELOP_BLEND_LINEARLIGHT },
2313 { NC_("blendmode", "pinlight"), DEVELOP_BLEND_PINLIGHT },
2314 { NC_("blendmode", "lightness"), DEVELOP_BLEND_LIGHTNESS },
2315 { NC_("blendmode", "chromaticity"), DEVELOP_BLEND_CHROMATICITY },
2316 { NC_("blendmode", "hue"), DEVELOP_BLEND_HUE },
2317 { NC_("blendmode", "color"), DEVELOP_BLEND_COLOR },
2318 { NC_("blendmode", "coloradjustment"), DEVELOP_BLEND_COLORADJUST },
2319 { NC_("blendmode", "Lab lightness"), DEVELOP_BLEND_LAB_LIGHTNESS },
2320 { NC_("blendmode", "Lab color"), DEVELOP_BLEND_LAB_COLOR },
2321 { NC_("blendmode", "Lab L-channel"), DEVELOP_BLEND_LAB_L },
2322 { NC_("blendmode", "Lab a-channel"), DEVELOP_BLEND_LAB_A },
2323 { NC_("blendmode", "Lab b-channel"), DEVELOP_BLEND_LAB_B },
2324 { NC_("blendmode", "HSV value"), DEVELOP_BLEND_HSV_VALUE },
2325 { NC_("blendmode", "HSV color"), DEVELOP_BLEND_HSV_COLOR },
2326 { NC_("blendmode", "RGB red channel"), DEVELOP_BLEND_RGB_R },
2327 { NC_("blendmode", "RGB green channel"), DEVELOP_BLEND_RGB_G },
2328 { NC_("blendmode", "RGB blue channel"), DEVELOP_BLEND_RGB_B },
2329 { NC_("blendmode", "divide"), DEVELOP_BLEND_DIVIDE },
2330 { NC_("blendmode", "geometric mean"), DEVELOP_BLEND_GEOMETRIC_MEAN },
2331 { NC_("blendmode", "harmonic mean"), DEVELOP_BLEND_HARMONIC_MEAN },
2332
2334 { NC_("blendmode", "difference (deprecated)"), DEVELOP_BLEND_DIFFERENCE },
2335 { NC_("blendmode", "subtract inverse (deprecated)"), DEVELOP_BLEND_SUBTRACT_INVERSE },
2336 { NC_("blendmode", "divide inverse (deprecated)"), DEVELOP_BLEND_DIVIDE_INVERSE },
2337 { "", 0 } };
2338
2340 = { { NC_("blendoperation", "normal"), 0 },
2341 { NC_("blendoperation", "reverse"), DEVELOP_BLEND_REVERSE },
2342 { "", 0 } };
2343
2345 = { { N_("default"), DEVELOP_BLEND_CS_NONE },
2346 { N_("RAW"), DEVELOP_BLEND_CS_RAW },
2347 { N_("Lab"), DEVELOP_BLEND_CS_LAB },
2348 { N_("RGB (display)"), DEVELOP_BLEND_CS_RGB_DISPLAY },
2349 { N_("RGB (scene)"), DEVELOP_BLEND_CS_RGB_SCENE },
2350 { "", 0 } };
2351
2353 = { { N_("None"), 0 },
2354 { N_("Uniform"), 1 },
2355 { N_("Parametric mask"), 2 },
2356 { N_("Drawn mask"), 3 },
2357 { N_("Drawn & parametric mask"), 4 },
2358 { N_("Reuse an existing mask"), 5 },
2359 { "", 0 } };
2360
2362 = { { N_("exclusive"), DEVELOP_COMBINE_NORM_EXCL },
2363 { N_("inclusive"), DEVELOP_COMBINE_NORM_INCL },
2364 { N_("exclusive & inverted"), DEVELOP_COMBINE_INV_EXCL },
2365 { N_("inclusive & inverted"), DEVELOP_COMBINE_INV_INCL },
2366 { "", 0 } };
2367
2369 = { { N_("output before blur"), DEVELOP_MASK_GUIDE_OUT_BEFORE_BLUR },
2370 { N_("input before blur"), DEVELOP_MASK_GUIDE_IN_BEFORE_BLUR },
2371 { N_("output after blur"), DEVELOP_MASK_GUIDE_OUT_AFTER_BLUR },
2372 { N_("input after blur"), DEVELOP_MASK_GUIDE_IN_AFTER_BLUR },
2373 { "", 0 } };
2374
2376 = { { N_("off"), DEVELOP_COMBINE_NORM },
2377 { N_("on"), DEVELOP_COMBINE_INV },
2378 { "", 0 } };
2379
2380// clang-format off
2381// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
2382// vim: shiftwidth=2 expandtab tabstop=2 cindent
2383// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
2384// 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:640
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:1160
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:560
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:1014
const dt_develop_name_value_t dt_develop_invert_mask_names[]
Definition blend.c:2376
const dt_develop_name_value_t dt_develop_mask_mode_names[]
Definition blend.c:2353
void dt_develop_blend_free_cl_global(void)
Definition blend.c:1685
void dt_develop_blend_init_cl_global(void)
Definition blend.c:1654
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:466
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:510
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:1720
static uint32_t _blend_legacy_blend_mode(uint32_t legacy_blend_mode)
Definition blend.c:1751
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:2264
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:1714
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:1778
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:537
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:704
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:2345
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:1741
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:673
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:2340
static void _develop_blend_process_free_region(float *const restrict input)
Definition blend.c:532
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:600
const dt_develop_name_value_t dt_develop_combine_masks_names[]
Definition blend.c:2362
const dt_develop_name_value_t dt_develop_blend_mode_names[]
Definition blend.c:2298
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:650
const dt_develop_name_value_t dt_develop_feathering_guide_names[]
Definition blend.c:2369
static void _blend_process_cl_exchange(cl_mem *a, cl_mem *b)
Definition blend.c:1153
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_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:1825
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)
#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:2085
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_raster_result_t dt_masks_group_render_roi(dt_iop_module_t *module, dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, dt_masks_form_t *form, const dt_iop_roi_t *roi, float *buffer)
Definition group.c:938
dt_masks_form_t * dt_masks_get_from_id_ext(GList *forms, int id)
Definition masks.c:899
dt_masks_form_t * dt_masks_get_from_id(dt_develop_t *dev, int id)
Definition masks.c:909
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
int dt_opencl_enqueue_kernel_2d(const int dev, const int kernel, const size_t *sizes)
Definition opencl.c:2554
void * dt_opencl_alloc_device_buffer(const int devid, const size_t size)
Definition opencl.c:2970
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:2581
void * dt_opencl_alloc_device(const int devid, const int width, const int height, const int bpp)
Definition opencl.c:2894
int dt_opencl_create_kernel(const int prog, const char *name)
Definition opencl.c:2448
void * dt_opencl_copy_host_to_device_constant(const int devid, const size_t size, void *host)
Definition opencl.c:2750
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:2679
void dt_opencl_free_kernel(const int kernel)
Definition opencl.c:2491
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:2545
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:2587
void dt_opencl_release_mem_object(cl_mem mem)
Definition opencl.c:2805
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:2634
#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
void dt_pipeline_message(const char *format,...)
Everything the pixel pipeline says to whoever is watching: messages for the user, and the busy banner...
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)
Increase/Decrease the reference count on the cache line as to prevent LRU item removal....
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.
int dt_dev_pixelpipe_cache_remove(const gboolean force, dt_pixel_cache_entry_t *cache_entry)
Arbitrarily remove the cache entry matching hash. Entries having a reference count > 0 (inter-thread ...
#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_iop_buffer_dsc_t dsc_in
dt_dev_pixelpipe_type_t type
gboolean store_all_raster_masks
GArray * raster_mask_hashes
float blendif_parameters[4 *DEVELOP_BLENDIF_SIZE]
Definition blend.h:231
float blendif_boost_factors[DEVELOP_BLENDIF_SIZE]
Definition blend.h:232
int32_t gui_attached
Definition develop.h:167
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
unsigned int channels
Definition format.h:83
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:214