Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
imageop.c
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2009-2014 johannes hanika.
4 Copyright (C) 2010-2011 Bruce Guenter.
5 Copyright (C) 2010-2012 Henrik Andersson.
6 Copyright (C) 2010 Stuart Henderson.
7 Copyright (C) 2011 Antony Dovgal.
8 Copyright (C) 2011 Brian Teague.
9 Copyright (C) 2011-2012 Jérémy Rosen.
10 Copyright (C) 2011 Robert Bieber.
11 Copyright (C) 2011 Rostyslav Pidgornyi.
12 Copyright (C) 2011-2020 Tobias Ellinghaus.
13 Copyright (C) 2011-2015, 2017, 2019 Ulrich Pegelow.
14 Copyright (C) 2012-2014, 2019-2022 Aldric Renaudin.
15 Copyright (C) 2012 Edouard Gomez.
16 Copyright (C) 2012-2013, 2015, 2018, 2020 parafin.
17 Copyright (C) 2012-2013, 2018-2022 Pascal Obry.
18 Copyright (C) 2012 Richard Wonka.
19 Copyright (C) 2013-2016 Roman Lebedev.
20 Copyright (C) 2013 Simon Spannagel.
21 Copyright (C) 2013 Thomas Pryds.
22 Copyright (C) 2014, 2017, 2021 Dan Torop.
23 Copyright (C) 2014 Mikhail Trishchenkov.
24 Copyright (C) 2014-2016 Pedro Côrte-Real.
25 Copyright (C) 2017 Dominik Markiewicz.
26 Copyright (C) 2017-2019 Edgardo Hoszowski.
27 Copyright (C) 2017-2020 Heiko Bauke.
28 Copyright (C) 2017 Peter Budai.
29 Copyright (C) 2018 Matthieu Moy.
30 Copyright (C) 2018 rawfiner.
31 Copyright (C) 2019-2026 Aurélien PIERRE.
32 Copyright (C) 2019-2022 Diederik Ter Rahe.
33 Copyright (C) 2019 Jacques Le Clerc.
34 Copyright (C) 2020-2022 Chris Elston.
35 Copyright (C) 2020-2022 Hanno Schwalm.
36 Copyright (C) 2020 Harold le Clément de Saint-Marcq.
37 Copyright (C) 2020-2021 Hubert Kowalski.
38 Copyright (C) 2020-2021 Marco.
39 Copyright (C) 2020 Philippe Weyland.
40 Copyright (C) 2020-2021 Ralf Brown.
41 Copyright (C) 2021 Mark-64.
42 Copyright (C) 2021-2022 Philipp Lutz.
43 Copyright (C) 2021 Sakari Kapanen.
44 Copyright (C) 2022 Martin Bařinka.
45 Copyright (C) 2022 Miloš Komarčević.
46 Copyright (C) 2022 Nicolas Auffray.
47 Copyright (C) 2023 Alynx Zhou.
48 Copyright (C) 2023 Luca Zulberti.
49 Copyright (C) 2025-2026 Guillaume Stutin.
50 Copyright (C) 2025 Miguel Moquillon.
51
52 darktable is free software: you can redistribute it and/or modify
53 it under the terms of the GNU General Public License as published by
54 the Free Software Foundation, either version 3 of the License, or
55 (at your option) any later version.
56
57 darktable is distributed in the hope that it will be useful,
58 but WITHOUT ANY WARRANTY; without even the implied warranty of
59 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
60 GNU General Public License for more details.
61
62 You should have received a copy of the GNU General Public License
63 along with darktable. If not, see <http://www.gnu.org/licenses/>.
64*/
65
66#include "develop/imageop_gui.h"
67#include "darktable.h"
69#include "common/conf.h"
70#include "common/sentry.h"
71#include "common/telemetry.h"
72#include "develop/imageop.h"
73#include "widgets/bauhaus.h"
74#include "common/collection.h"
76#include "database/database.h"
79#include "metadata/exif.h"
80#include "history/history.h"
81#include "common/imagebuf.h"
83#include "pixel/interpolation.h"
84#include "common/module.h"
85#include "common/opencl.h"
87#include "control/control.h"
88#include "control/signal.h"
89#include "develop/blend.h"
90#include "develop/blend_gui.h"
91#include "develop/develop.h"
92#include "develop/dev_history.h" // dt_dev_history_get_last_item_by_module(), dt_dev_get_history_end_ext()
93#include "pixel/format.h"
94#include "develop/masks.h"
95#include "develop/tiling.h"
96#include "widgets/gdkkeys.h"
97#include "gui/presets.h"
98#include "widgets/button.h"
99#include "widgets/expander.h"
100
102#include "gui/application.h"
103#include "develop/gui_throttle.h"
104#include "gui/presets.h"
105#ifdef GDK_WINDOWING_QUARTZ
106#endif
107
108#include "common/hash.h"
110
111#include <assert.h>
112#include <gmodule.h>
113#include <math.h>
114#include <complex.h>
115#include <stdlib.h>
116#include "widgets/container.h"
117#include "widgets/label.h"
118#include "widgets/popup.h"
119#include "widgets/widget_style.h"
120
121#include <string.h>
122#include <strings.h>
123#include <time.h>
124#include "widgets/togglebutton.h"
125
126
132
133
134float dt_dev_get_module_scale(const dt_dev_pixelpipe_t *const pipe, const dt_iop_roi_t *const roi_in)
135{
136 return pipe->iscale / roi_in->scale;
137}
138
139uint32_t dt_dev_get_roi_filters(const dt_dev_pixelpipe_iop_t *const piece, const dt_iop_roi_t *const roi_in)
140{
141 return dt_rawspeed_crop_dcraw_filters(piece->dsc_in.filters, roi_in->x, roi_in->y);
142}
143
144
154
155static void _iop_modify_roi_in(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe,
156 struct dt_dev_pixelpipe_iop_t *piece,
157 const dt_iop_roi_t *roi_out, dt_iop_roi_t *roi_in)
158{
159 *roi_in = *roi_out;
160}
161
162static void _iop_modify_roi_out(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe,
163 struct dt_dev_pixelpipe_iop_t *piece,
164 dt_iop_roi_t *roi_out, const dt_iop_roi_t *roi_in)
165{
166 *roi_out = *roi_in;
167}
168
169/* default group for modules which do not implement the default_group() function */
170static int default_default_group(void)
171{
172 return IOP_GROUP_TECHNICAL;
173}
174
175/* default flags for modules which does not implement the flags() function */
176static int default_flags(void)
177{
178 return 0;
179}
180
181/* default operation tags for modules which does not implement the flags() function */
183{
184 return 0;
185}
186
187/* default operation tags filter for modules which does not implement the flags() function */
189{
190 return 0;
191}
192
193static const char **default_description(struct dt_iop_module_t *self)
194{
195 return NULL;
196}
197
198static const char *default_aliases(void)
199{
200 return "";
201}
202
203static const char *default_deprecated_msg(void)
204{
205 return NULL;
206}
207
208static gboolean default_has_defaults(struct dt_iop_module_t *self)
209{
210 return memcmp(self->params, self->default_params, self->params_size) == 0;
211}
212
214 const dt_dev_pixelpipe_iop_t *piece)
215{
216 (void)self;
217 (void)pipe;
218 (void)piece;
219 return FALSE;
220}
221
222static void default_commit_params(struct dt_iop_module_t *self, dt_iop_params_t *params,
224{
225 memcpy(piece->data, params, self->params_size);
226}
227
228// WARNING: this works only if the data struct has the same size
229// as the param structure. You need to implement your own IOP module
230// method if they don't match !!!
233{
234 size_t data_size = (size_t)self->params_size;
235 piece->data = dt_calloc_align(data_size);
236 piece->data_size = data_size;
237}
238
241{
242 dt_free_align(piece->data);
243 piece->data = NULL;
244}
245
247{
249}
250
252{
253 dt_free(module->params);
254 dt_free(module->default_params);
255}
256
257
259 const dt_dev_pixelpipe_iop_t *piece, float *points,
260 size_t points_count)
261{
262 (void)self;
263 (void)pipe;
264 (void)piece;
265 (void)points;
266 (void)points_count;
267 return 1;
268}
270 const dt_dev_pixelpipe_iop_t *piece, float *points,
271 size_t points_count)
272{
273 (void)self;
274 (void)pipe;
275 (void)piece;
276 (void)points;
277 (void)points_count;
278 return 1;
279}
280
281static int default_process(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe,
282 const struct dt_dev_pixelpipe_iop_t *piece,
283 const void *const i, void *const o)
284{
285 const struct dt_iop_roi_t *const roi_in = &piece->roi_in;
286 const struct dt_iop_roi_t *const roi_out = &piece->roi_out;
287 if(roi_in->width <= 1 || roi_in->height <= 1 || roi_out->width <= 1 || roi_out->height <= 1) return 0;
288 return self->process_plain(self, pipe, piece, i, o);
289}
290
292{
293 return NULL;
294}
296{
297 return NULL;
298}
299static void *default_get_p(const void *param, const char *name)
300{
301 return NULL;
302}
304{
305 return NULL;
306}
307
309{
310 size_t param_size = module->so->get_introspection()->size;
311 module->params_size = param_size;
312 /* Keep ownership explicit: if init is re-entered on the same instance,
313 * release previous params before rebuilding defaults from introspection. */
314 if(!IS_NULL_PTR(module->params))
315 {
316 dt_free(module->params);
317 module->params = NULL;
318 }
319 if(!IS_NULL_PTR(module->default_params))
320 {
321 dt_free(module->default_params);
322 module->default_params = NULL;
323 }
324 module->params = (dt_iop_params_t *)calloc(1, param_size);
325 module->default_params = (dt_iop_params_t *)calloc(1, param_size);
326
327 module->default_enabled = 0;
328
329 dt_introspection_field_t *i = module->so->get_introspection_linear();
330 while(i->header.type != DT_INTROSPECTION_TYPE_NONE)
331 {
332 switch(i->header.type)
333 {
335 *(float*)((uint8_t *)module->default_params + i->header.offset) = i->Float.Default;
336 break;
338 *(int*)((uint8_t *)module->default_params + i->header.offset) = i->Int.Default;
339 break;
341 *(unsigned int*)((uint8_t *)module->default_params + i->header.offset) = i->UInt.Default;
342 break;
344 *(unsigned short*)((uint8_t *)module->default_params + i->header.offset) = i->UShort.Default;
345 break;
347 *(int*)((uint8_t *)module->default_params + i->header.offset) = i->Enum.Default;
348 break;
350 *(gboolean*)((uint8_t *)module->default_params + i->header.offset) = i->Bool.Default;
351 break;
353 *(char*)((uint8_t *)module->default_params + i->header.offset) = i->Char.Default;
354 break;
356 memset((uint8_t *)module->default_params + i->header.offset, 0, i->header.size);
357 break;
359 {
360 if(i->Array.type == DT_INTROSPECTION_TYPE_CHAR) break;
361
362 size_t element_size = i->Array.field->header.size;
363 if(element_size % sizeof(int))
364 {
365 int8_t *p = (int8_t *)module->default_params + i->header.offset;
366 for (size_t c = element_size; c < i->header.size; c++, p++)
367 p[element_size] = *p;
368 }
369 else
370 {
371 element_size /= sizeof(int);
372 size_t num_ints = i->header.size / sizeof(int);
373
374 int *p = (int *)((uint8_t *)module->default_params + i->header.offset);
375 for (size_t c = element_size; c < num_ints; c++, p++)
376 p[element_size] = *p;
377 }
378 }
379 break;
381 // ignore STRUCT; nothing to do
382 break;
383 default:
384 fprintf(stderr, "unsupported introspection type \"%s\" encountered in dt_iop_default_init (field %s)\n", i->header.type_name, i->header.field_name);
385 break;
386 }
387
388 i++;
389 }
390}
391
392
393/* The bauhaus widgets ask a module to make itself visible before grabbing focus inside it.
394 * For an IOP that means expanding a collapsed expander, and dropping stale focus first --
395 * both develop/ concerns, which is why this lives here and not in the widget. */
397{
398 dt_iop_module_t *module = (dt_iop_module_t *)m;
399 if(IS_NULL_PTR(module)) return;
400
401 if(module->gui && !IS_NULL_PTR(module->gui->expander))
402 {
403 g_object_set_data(G_OBJECT(module->gui->expander), "dt-modulegroups-switch-from-active-once",
404 GINT_TO_POINTER(TRUE));
406 }
407
408 // If the module is already marked focused, modulegroups may not re-emit its focus signal
409 // and tab visibility can stay stale. Drop focus once so the next request replays the
410 // full focus/update sequence.
411 if(!IS_NULL_PTR(dt_dev_get_global()) && dt_dev_get_global()->gui_module == module)
413}
414
415int default_iop_focus(dt_gui_module_t *m, gboolean toggle)
416{
417 dt_iop_module_t *module = (dt_iop_module_t *) m;
418
419 // Expand and scroll
420 if(module->dev->gui_module != module)
421 {
422 dt_iop_request_focus(module);
424 }
425 else if(toggle)
426 {
427 module->dev->gui_module = NULL;
430 }
431
432 return 1;
433}
434
455 const dt_iop_module_static_entry_t *const entry)
456{
457 const char *const module_name = entry->op;
458 g_strlcpy(module->op, module_name, sizeof(module->op));
459
460 entry->fill_so(module);
461
462#define INCLUDE_API_FROM_MODULE_STATIC_DEFAULTS
463#include "iop/iop_api.h"
464
465 if(IS_NULL_PTR(module->init)) module->init = dt_iop_default_init;
466 if(IS_NULL_PTR(module->modify_roi_in)) module->modify_roi_in = _iop_modify_roi_in;
467 if(IS_NULL_PTR(module->modify_roi_out)) module->modify_roi_out = _iop_modify_roi_out;
468
469 #ifdef HAVE_OPENCL
470 if(IS_NULL_PTR(module->process_tiling_cl)) module->process_tiling_cl = dt_opencl_is_inited() ? default_process_tiling_cl : NULL;
471 if(!dt_opencl_is_inited()) module->process_cl = NULL;
472 #endif // HAVE_OPENCL
473
474 module->process_plain = module->process;
475 module->process = default_process;
476
477 module->data = NULL;
478
479 // the introspection api
480 module->have_introspection = FALSE;
481 if(module->introspection_init)
482 {
483 if(!module->introspection_init(module, DT_INTROSPECTION_VERSION))
484 {
485 // set the introspection related fields in module
486 module->have_introspection = TRUE;
487
488 if(module->get_p == default_get_p ||
489 module->get_f == default_get_f ||
490 module->get_introspection_linear == default_get_introspection_linear ||
491 module->get_introspection == default_get_introspection)
492 {
493 fprintf(stderr,
494 "[iop_load_module] `%s' claims introspection but did not replace the default"
495 " accessors\n", module_name);
496 return 1;
497 }
498 }
499 else
500 fprintf(stderr, "[iop_load_module] failed to initialize introspection for operation `%s'\n", module_name);
501 }
502
503 if(module->init_global) module->init_global(module);
504 return 0;
505}
506
507/* The old inline widget members were zeroed here at load; the gui struct is calloc'd by
508 * dt_iop_gui_init() when (and only when) a GUI attaches, so a headless load must not
509 * touch module->gui at all -- it is NULL by design. */
511{
512 module->dev = dev;
513 module->hide_enable_button = 0;
514 module->request_color_pick = DT_REQUEST_COLORPICK_OFF;
515 module->request_histogram = DT_REQUEST_ONLY_IN_GUI;
516 module->histogram_stats.bins_count = 0;
517 module->histogram_stats.pixels = 0;
518 module->multi_priority = 0;
519 module->iop_order = 0;
520 for(int k = 0; k < 3; k++)
521 {
522 module->picked_color[k] = module->picked_output_color[k] = 0.0f;
523 module->picked_color_min[k] = module->picked_output_color_min[k] = 666.0f;
524 module->picked_color_max[k] = module->picked_output_color_max[k] = -666.0f;
525 }
526 module->histogram_cst = IOP_CS_NONE;
527 module->histogram = NULL;
528 module->histogram_max[0] = module->histogram_max[1] = module->histogram_max[2] = module->histogram_max[3]
529 = 0;
530 module->histogram_middle_grey = FALSE;
531 module->request_mask_display = DT_DEV_PIXELPIPE_DISPLAY_NONE;
532 module->bypass_cache = FALSE;
533 module->bypass_cache_variant = 0;
534 module->enabled = module->default_enabled = module->workflow_enabled = 0; // all modules disabled by default.
535 g_strlcpy(module->op, so->op, 20);
536 module->raster_mask.source.users = g_hash_table_new(NULL, NULL);
537 module->raster_mask.source.masks = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, dt_free_gpointer);
538 module->raster_mask.sink.source = NULL;
539 module->raster_mask.sink.id = 0;
540
541 module->so = so;
542
543#define INCLUDE_API_FROM_MODULE_LOAD_BY_SO
544#include "iop/iop_api.h"
545
546 module->version = so->version;
547 module->process_plain = so->process_plain;
548 module->have_introspection = so->have_introspection;
549
550
551 module->global_data = so->data;
552
553 // now init the instance:
554 module->init(module);
555 module->hash = DT_PIXELPIPE_CACHE_HASH_INVALID;
556 module->blendop_hash = DT_PIXELPIPE_CACHE_HASH_INVALID;
557
558 if(module->params_size == 0)
559 {
560 fprintf(stderr, "[iop_load_module] `%s' needs to have a params size > 0!\n", so->op);
561 return 1; // empty params hurt us in many places, just add a dummy value
562 }
563
564 /* Allocate params only when module init did not allocate them already.
565 * Some init paths (notably default_init) already own the params buffers. */
566 if(IS_NULL_PTR(module->params))
567 module->params = calloc(1, module->params_size);
568 if(IS_NULL_PTR(module->default_params))
569 module->default_params = calloc(1, module->params_size);
570 module->blend_params = calloc(1, sizeof(dt_develop_blend_params_t));
571 module->default_blendop_params = calloc(1, sizeof(dt_develop_blend_params_t));
572
573 // Don't init defaults here, it's done when reading/initing history
574
575 /* pass on the dt_gui_module_t args for bauhaus widgets
576 * only when a GUI lifetime exists for this module instance. */
577 if(IS_NULL_PTR(module->dev) || module->dev->gui_attached)
578 {
579 module->common_fields.name = delete_underscore(module->name());
580 module->common_fields.view = g_strdup(_("Darkroom")); // IOP modules belong necessarily to darkroom
581 }
582 else
583 {
584 module->common_fields.name = NULL;
585 module->common_fields.view = NULL;
586 }
587 module->common_fields.widget_list = NULL;
588 module->common_fields.widget_list_bh = NULL;
589 module->common_fields.focus = module->iop_focus;
590 module->common_fields.ensure_visible = _iop_ensure_visible;
591 module->common_fields.deprecated = (module->flags() & IOP_FLAGS_DEPRECATED) == IOP_FLAGS_DEPRECATED;
592
593 return 0;
594}
595
604void dt_iop_init_pipe(struct dt_iop_module_t *module, struct dt_dev_pixelpipe_t *pipe,
605 struct dt_dev_pixelpipe_iop_t *piece)
606{
607 if(IS_NULL_PTR(module) || IS_NULL_PTR(piece)) return;
608
609 if(!IS_NULL_PTR(module->init_pipe)) module->init_pipe(module, pipe, piece);
610
611 if(piece->data_size > 0 && IS_NULL_PTR(piece->data))
612 {
614 "[dt_iop_init_pipe] `%s' could not allocate its %" G_GSIZE_FORMAT
615 " bytes of node storage; the node stays disabled\n", module->op, piece->data_size);
616 piece->data_size = 0;
617 piece->enabled = 0;
618 }
619
621 if(IS_NULL_PTR(piece->blendop_data))
622 {
624 "[dt_iop_init_pipe] `%s' could not allocate blend storage; the node stays disabled\n",
625 module->op);
626 piece->enabled = 0;
627 }
628}
629
642 struct dt_dev_pixelpipe_iop_t *piece)
643{
644 if(IS_NULL_PTR(piece)) return;
645
646 if(IS_NULL_PTR(module))
647 {
649 "[dt_iop_cleanup_pipe] missing module, skipping module pipe cleanup\n");
650 }
651 else if(IS_NULL_PTR(pipe))
652 {
654 "[dt_iop_cleanup_pipe] missing pipe for `%s`, skipping module pipe cleanup\n",
655 module->op);
656 }
657 else
658 {
659 dt_iop_module_so_t *module_so = module->so;
660 gboolean module_so_loaded = FALSE;
661
662 /* Search the process-owned descriptor list by address before reading the
663 * candidate. A removed instance may outlive its GUI, but its descriptor
664 * must remain one of the objects loaded at startup. */
665 for(GList *iop = g_list_first(darktable.iop); iop; iop = g_list_next(iop))
666 {
667 if(iop->data == module_so)
668 {
669 module_so_loaded = TRUE;
670 break;
671 }
672 }
673
674 if(!module_so_loaded)
676 "[dt_iop_cleanup_pipe] invalid shared-object descriptor %p, skipping module pipe cleanup\n",
677 (void *)module_so);
678 else if(module->cleanup_pipe != module_so->cleanup_pipe)
680 "[dt_iop_cleanup_pipe] stale cleanup callback for `%s`, skipping module pipe cleanup\n",
681 module_so->op);
682 else
683 module_so->cleanup_pipe(module, pipe, piece);
684 }
685
686 if(!IS_NULL_PTR(piece->blendop_data))
687 {
689 piece->blendop_data = NULL;
690 }
691}
692
694 gboolean enable, gboolean write_history, const char *reason)
695{
696 if(IS_NULL_PTR(dev)) return FALSE;
697
699 if(write_history) dt_dev_add_history_item(dev, module, enable, TRUE);
700
701 if(!IS_NULL_PTR(reason)) dt_ioppr_check_iop_order(dev, 0, reason);
702
704 return TRUE;
705}
706
708 const char *reason)
709{
710 if(!dt_ioppr_move_iop_before(module->dev, module, module_next)) return FALSE;
711 return dt_iop_gui_commit_iop_order_change(module->dev, module, TRUE, TRUE, reason);
712}
713
715 const char *reason)
716{
717 if(!dt_ioppr_move_iop_after(module->dev, module, module_prev)) return FALSE;
718 return dt_iop_gui_commit_iop_order_change(module->dev, module, TRUE, TRUE, reason);
719}
720
722{
723 gboolean is_hidden = TRUE;
724 if(!(module->flags() & IOP_FLAGS_HIDDEN))
725 {
726 if(IS_NULL_PTR(module->gui_init))
727 g_debug("Module '%s' is not hidden and lacks implementation of gui_init()...", module->op);
728 else if(!module->gui_cleanup)
729 g_debug("Module '%s' is not hidden and lacks implementation of gui_cleanup()...", module->op);
730 else
731 is_hidden = FALSE;
732 }
733 return is_hidden;
734}
735
737{
738 return dt_iop_so_is_hidden(module->so);
739}
740
742{
743 if(IS_NULL_PTR(iop)) return FALSE;
744 if(iop->multi_priority == 0) return TRUE;
745
746 dt_develop_t *const dev = iop->dev;
747 if(IS_NULL_PTR(dev)) return FALSE;
748
750 const gboolean exists = !IS_NULL_PTR(
753
754 return exists;
755}
756
757/* Whether any history item at all names the module, regardless of where the history cursor sits.
758 * That is a different question from dt_iop_module_instance_exists(): a module the user has
759 * touched and then undone past is still part of the pipeline they are working on. */
761{
762 dt_develop_t *const dev = module->dev;
763 if(IS_NULL_PTR(dev)) return FALSE;
764
765 gboolean found = FALSE;
767 for(const GList *history = g_list_last(dev->history); history && !found;
768 history = g_list_previous(history))
769 {
770 const dt_dev_history_item_t *item = (const dt_dev_history_item_t *)history->data;
771 found = (item->module == module);
772 }
774
775 return found;
776}
777
779{
780 if(IS_NULL_PTR(iop) || dt_iop_is_hidden(iop)) return FALSE;
781 if(!iop->enabled && !_module_carries_history(iop)) return FALSE;
783}
784
786{
787 if(IS_NULL_PTR(iop) || IS_NULL_PTR(iop->blend_params)) return FALSE;
788 const int flags = iop->flags();
790}
791
793{
794 // Suppress GUI callbacks while a module's reload_defaults() rewrites widget defaults. This is
795 // a no-op off the GUI thread (worker-thread thumbnail/export devs have no widgets, so they
796 // must never touch -- and race/drift -- the shared depth); the central API enforces that.
797 // The previous root cause of NULL-bauhaus-widget crashes was exactly this counter drifting
798 // (Sentry #129494618, #129578628, #129908540). Scope the freeze to the params work so the
799 // header update below still runs unsuppressed, exactly as before.
800 {
802
803 if(module->reload_defaults)
804 {
805 // report if reload_defaults was called unnecessarily => this should be considered a bug
806 // the whole point of reload_defaults is to update defaults _based on current image_
807 // any required initialisation should go in init (and not be performed repeatedly here)
808 if(module->dev)
809 {
810 module->reload_defaults(module);
811 dt_print(DT_DEBUG_PARAMS, "[params] defaults reloaded for %s\n", module->op);
812 }
813 else
814 {
815 fprintf(stderr, "reload_defaults should not be called without image.\n");
816 }
817 }
819 }
820
821 if(module->gui && module->gui->header) dt_iop_gui_update_header(module);
822}
823
824
825/* dt_gui_presets_add_generic() cannot name a blending space: init_presets() is handed the module
826 * type, and only an instance answers blend_colorspace(). Resolve every preset still carrying
827 * DEVELOP_BLEND_CS_NONE here, so the database, the history rows auto-applied presets become and
828 * every binary comparison against a module's blend params only ever see a real space. There is
829 * no pipe here, so the space is the one of a module in the working space. The rows are listed
830 * again rather than reusing the caller's list, which was read before the legacy upgrades above
831 * rewrote some of them. */
833{
834 if(!(module_so->flags() & IOP_FLAGS_SUPPORTS_BLENDING)) return;
835
836 dt_iop_module_t *module = NULL;
837 GList *presets = dt_preset_repository_list_for_upgrade(module_so->op);
838 for(GList *l = presets; l; l = g_list_next(l))
839 {
840 const dt_module_preset_t *preset = (const dt_module_preset_t *)l->data;
841 if(IS_NULL_PTR(preset->blendop_params) || preset->blendop_version != dt_develop_blend_version()
842 || preset->blendop_params_size != (int)sizeof(dt_develop_blend_params_t))
843 continue;
844
845 dt_develop_blend_params_t blend_params;
846 memcpy(&blend_params, preset->blendop_params, sizeof(blend_params));
847 if(blend_params.blend_cst != DEVELOP_BLEND_CS_NONE) continue;
848
849 if(IS_NULL_PTR(module))
850 {
851 module = (dt_iop_module_t *)calloc(1, sizeof(dt_iop_module_t));
852 if(IS_NULL_PTR(module) || dt_iop_load_module_by_so(module, module_so, NULL))
853 {
854 dt_free(module);
855 break;
856 }
857 }
858
859 // a module can support blending and still answer IOP_CS_NONE, which has no space to write back
860 dt_develop_blend_resolve_default_colorspace(module, &blend_params);
861 if(blend_params.blend_cst == DEVELOP_BLEND_CS_NONE) continue;
863 sizeof(blend_params));
864 }
865 g_list_free_full(presets, dt_module_preset_free);
866
867 if(!IS_NULL_PTR(module))
868 {
869 dt_iop_cleanup_module(module);
870 dt_free(module);
871 }
872}
873
874static void _init_presets(dt_iop_module_so_t *module_so)
875{
876 // Skip auto-preset regeneration when the build + UI language haven't changed.
877 if(module_so->init_presets && dt_gui_presets_autogen_enabled())
878 module_so->init_presets(module_so);
879
880 // this seems like a reasonable place to check for and update legacy
881 // presets.
882
883 const int32_t module_version = module_so->version();
884
885 // The rows are read out in full first: the loop below writes back to data.presets, and it
886 // used to do so while still stepping a cursor over that same table.
887 GList *presets = dt_preset_repository_list_for_upgrade(module_so->op);
888 for(GList *l = presets; l; l = g_list_next(l))
889 {
890 const dt_module_preset_t *preset = (const dt_module_preset_t *)l->data;
891 const char *name = preset->name;
892 int32_t old_params_version = preset->op_version;
893 const void *old_params = preset->op_params;
894 const int32_t old_params_size = preset->op_params_size;
895 const int32_t old_blend_params_version = preset->blendop_version;
896 const void *old_blend_params = preset->blendop_params;
897 const int32_t old_blend_params_size = preset->blendop_params_size;
898
899 if(old_params_version == 0)
900 {
901 // this preset doesn't have a version. go digging through the database
902 // to find a history entry that matches the preset params, and get
903 // the module version from that.
904
905 old_params_version = dt_history_repository_find_version_for_params(module_so->op, old_params,
906 old_params_size);
907 if(old_params_version == 0)
908 {
909 fprintf(stderr, "[imageop_init_presets] WARNING: Could not find versioning information for '%s' "
910 "preset '%s'\nUntil some is found, the preset will be unavailable.\n(To make it "
911 "return, please load an image that uses the preset.)\n",
912 module_so->op, name);
913 continue;
914 }
915
916 // we found an old params version. Update the database with it.
917
918 fprintf(stderr, "[imageop_init_presets] Found version %d for '%s' preset '%s'\n", old_params_version,
919 module_so->op, name);
920
921 // ONLY the version: this preset's blob is already right, and a setter that also wrote
922 // op_params would overwrite every same-named preset at every other version with it.
923 dt_preset_repository_set_module_version(module_so->op, name, old_params_version);
924 }
925
926 if(module_version > old_params_version && !IS_NULL_PTR(module_so->legacy_params))
927 {
928 // we need a dt_iop_module_t for legacy_params()
929 dt_iop_module_t *module;
930 module = (dt_iop_module_t *)calloc(1, sizeof(dt_iop_module_t));
931 if(dt_iop_load_module_by_so(module, module_so, NULL))
932 {
933 dt_free(module);
934 continue;
935 }
936/*
937 module->init(module);
938 if(module->params_size == 0)
939 {
940 dt_iop_cleanup_module(module);
941 dt_free(module);
942 continue;
943 }
944 // we call reload_defaults() in case the module defines it
945 if(module->reload_defaults) module->reload_defaults(module); // why not call dt_iop_reload_defaults? (if needed at all)
946*/
947
948 const int32_t new_params_size = module->params_size;
949 void *new_params = calloc(1, new_params_size);
950
951 // convert the old params to new
952 if(module->legacy_params(module, old_params, old_params_version, new_params, module_version))
953 {
954 dt_free(new_params);
955 dt_iop_cleanup_module(module);
956 dt_free(module);
957 continue;
958 }
959
960 fprintf(stderr, "[imageop_init_presets] updating '%s' preset '%s' from version %d to version %d\nto:'%s'",
961 module_so->op, name, old_params_version, module_version,
962 dt_exif_xmp_encode(new_params, new_params_size, NULL));
963
964 // and write the new params back to the database
965 dt_preset_repository_update_module_params(module->op, name, module->version(), new_params,
966 new_params_size);
967
968 dt_free(new_params);
969 dt_iop_cleanup_module(module);
970 dt_free(module);
971 }
972 else if(module_version > old_params_version)
973 {
974 fprintf(stderr, "[imageop_init_presets] Can't upgrade '%s' preset '%s' from version %d to %d, no "
975 "legacy_params() implemented \n",
976 module_so->op, name, old_params_version, module_version);
977 }
978
979 if(IS_NULL_PTR(old_blend_params) || dt_develop_blend_version() > old_blend_params_version)
980 {
981 fprintf(stderr,
982 "[imageop_init_presets] updating '%s' preset '%s' from blendop version %d to version %d\n",
983 module_so->op, name, old_blend_params_version, dt_develop_blend_version());
984
985 // we need a dt_iop_module_t for dt_develop_blend_legacy_params()
986 // using dt_develop_blend_legacy_params_by_so won't help as we need "module" anyway
987 dt_iop_module_t *module;
988 module = (dt_iop_module_t *)calloc(1, sizeof(dt_iop_module_t));
989 if(dt_iop_load_module_by_so(module, module_so, NULL))
990 {
991 dt_free(module);
992 continue;
993 }
994
995 if(module->params_size == 0)
996 {
997 dt_iop_cleanup_module(module);
998 dt_free(module);
999 continue;
1000 }
1001 void *new_blend_params = malloc(sizeof(dt_develop_blend_params_t));
1002
1003 // convert the old blend params to new
1004 if(old_blend_params
1005 && dt_develop_blend_legacy_params(module, old_blend_params, old_blend_params_version,
1006 new_blend_params, dt_develop_blend_version(),
1007 old_blend_params_size) == 0)
1008 {
1009 // do nothing
1010 }
1011 else
1012 {
1013 memcpy(new_blend_params, module->default_blendop_params, sizeof(dt_develop_blend_params_t));
1014 }
1015
1016 // and write the new blend params back to the database
1018 new_blend_params, sizeof(dt_develop_blend_params_t));
1019
1020 dt_free(new_blend_params);
1021 dt_iop_cleanup_module(module);
1022 dt_free(module);
1023 }
1024 }
1025 g_list_free_full(presets, dt_module_preset_free);
1026
1028}
1029
1030
1031static void _init_module_so(void *m)
1032{
1033 dt_iop_module_so_t *module = (dt_iop_module_so_t *)m;
1034
1035 _init_presets(module);
1036
1037 // do not init accelerators if there is no gui
1038 if(dt_gui_get_global())
1039 {
1040 // create a gui and have the widgets register their accelerators
1041 dt_iop_module_t *module_instance = (dt_iop_module_t *)calloc(1, sizeof(dt_iop_module_t));
1042
1043 if(module->gui_init && !dt_iop_load_module_by_so(module_instance, module, NULL))
1044 {
1045 dt_iop_gui_init(module_instance);
1046
1047 static gboolean blending_accels_initialized = FALSE;
1048 if(!blending_accels_initialized)
1049 {
1050 dt_iop_colorspace_type_t cst = module->blend_colorspace(module_instance, NULL, NULL);
1051
1052 if((module->flags() & IOP_FLAGS_SUPPORTS_BLENDING) &&
1053 !(module->flags() & IOP_FLAGS_NO_MASKS) &&
1054 (cst == IOP_CS_LAB || dt_iop_colorspace_is_rgb(cst)))
1055 {
1056 dt_iop_gui_init_blending(module_instance);
1057 dt_iop_gui_cleanup_blending(module_instance);
1058
1059 blending_accels_initialized = TRUE;
1060 }
1061 }
1062
1063 dt_iop_gui_cleanup_module(module_instance);
1064
1065 dt_iop_cleanup_module(module_instance);
1066
1067 }
1068
1069 dt_free(module_instance);
1070 }
1071}
1072
1074{
1075 // Batch presets initialization in a single transaction to avoid per-module BEGIN/COMMIT overhead.
1077
1078 GList *modules = NULL;
1079 for(int k = 0; k < dt_iop_static_modules_count; k++)
1080 {
1082 dt_iop_module_so_t *module = (dt_iop_module_so_t *)calloc(1, sizeof(dt_iop_module_so_t));
1083
1084 if(_iop_load_module_static(module, entry))
1085 {
1086 dt_free(module);
1087 continue;
1088 }
1089
1090 modules = g_list_prepend(modules, module);
1091 _init_module_so(module);
1092 }
1093
1094 // The registry is emitted in a stable (alphabetical) order; keep it, rather than the
1095 // arbitrary readdir() order the directory scan used to produce. Pipe order comes from
1096 // iop_order and does not depend on this list's order at all.
1097 darktable.iop = g_list_reverse(modules);
1098
1100}
1101
1103{
1104 memset(module, 0, sizeof(dt_iop_module_t));
1105 if(dt_iop_load_module_by_so(module, module_so, dev))
1106 {
1107 dt_free(module);
1108 return 1;
1109 }
1110 return 0;
1111}
1112
1114{
1115 // Safety net: dt_iop_cleanup_module() is the one choke point every module teardown path (darkroom
1116 // leave(), studio_capture's viewer teardown, dev->alliop reclaim...) calls right before dt_free(module).
1117 // Some of those paths skip dt_iop_gui_cleanup_module() entirely (e.g. studio_capture never runs
1118 // gui_init on its modules), and dt_iop_gui_cleanup_module() itself only invokes the module's own
1119 // gui_cleanup() -- which does the DT_DEBUG_CONTROL_SIGNAL_DISCONNECT() calls -- when gui_data is
1120 // non-NULL. Any signal a module connected in gui_init() (module_moved_callback in lut3d.c,
1121 // _develop_ui_pipe_started_callback in toneequal.c...) is broadcast globally on the signal bus,
1122 // so a single missed disconnect leaves a dangling self pointer that a later, unrelated dev's signal
1123 // raise will invoke -- SIGSEGV on the freed instance. Disconnecting everything keyed on this module's
1124 // address here, unconditionally, guarantees no module can be invoked again once freed.
1126
1127 module->cleanup(module);
1128
1129 if(!IS_NULL_PTR(module->common_fields.name))
1130 {
1131 dt_free(module->common_fields.name);
1132 module->common_fields.name = NULL;
1133 }
1134 if(!IS_NULL_PTR(module->common_fields.view))
1135 {
1136 dt_free(module->common_fields.view);
1137 module->common_fields.view = NULL;
1138 }
1139
1140 dt_free(module->blend_params);
1142
1143 // don't have a picker pointing to a disappeared module
1144 dt_develop_t *const dev = dt_dev_get_global();
1145 if(dev
1146 && dev->color_picker.picker
1147 && dev->color_picker.picker->module == module)
1148 {
1149 dev->color_picker.picker = NULL;
1150 dev->color_picker.widget = NULL;
1151 dev->color_picker.module = NULL;
1152 dev->color_picker.enabled = FALSE;
1154 }
1155
1156 dt_free(module->histogram);
1157 g_hash_table_destroy(module->raster_mask.source.users);
1158 g_hash_table_destroy(module->raster_mask.source.masks);
1159 module->raster_mask.source.users = NULL;
1160 module->raster_mask.source.masks = NULL;
1161}
1162
1164{
1165 while(darktable.iop)
1166 {
1167 dt_iop_module_so_t *module = (dt_iop_module_so_t *)darktable.iop->data;
1168 if(module->cleanup_global) module->cleanup_global(module);
1169 dt_free(darktable.iop->data);
1170 darktable.iop = g_list_delete_link(darktable.iop, darktable.iop);
1171 }
1172}
1173
1174void dt_iop_set_mask_mode(dt_iop_module_t *module, int mask_mode)
1175{
1176 (void)mask_mode;
1177 static const int key = 0;
1178
1179 gboolean drawn_used = FALSE;
1180 gboolean parametric_used = FALSE;
1181 dt_develop_blend_get_mask_usage(module, module->blend_params, NULL, NULL, &drawn_used, &parametric_used);
1182
1183 if(drawn_used || parametric_used)
1184 {
1185 char *modulename = dt_history_item_get_name(module);
1186 g_hash_table_insert(module->raster_mask.source.masks, GINT_TO_POINTER(key), modulename);
1187 }
1188 else
1189 {
1190 g_hash_table_remove(module->raster_mask.source.masks, GINT_TO_POINTER(key));
1191 }
1192}
1193
1195{
1196 if(IS_NULL_PTR(module)) return FALSE;
1197
1198 const gboolean mask_mode_raster = module->blend_params
1199 && ((module->blend_params->mask_mode & DEVELOP_MASK_RASTER) == DEVELOP_MASK_RASTER);
1200 const gboolean has_raster_sink = (!IS_NULL_PTR(module->raster_mask.sink.source));
1201
1202 return mask_mode_raster || has_raster_sink;
1203}
1204
1205gboolean dt_iop_module_needs_mask_history_ext(const dt_iop_module_t *module, gboolean *raster, gboolean *drawn, gboolean *parametric)
1206{
1207 gboolean raster_used = FALSE;
1208 gboolean drawn_used = FALSE;
1209 gboolean parametric_used = FALSE;
1210 if(IS_NULL_PTR(module)) return FALSE;
1211
1212 const gboolean supports_blending
1213 = ((module->flags() & IOP_FLAGS_SUPPORTS_BLENDING) == IOP_FLAGS_SUPPORTS_BLENDING);
1214 const gboolean internal_masks = ((module->flags() & IOP_FLAGS_INTERNAL_MASKS) == IOP_FLAGS_INTERNAL_MASKS);
1215
1216 if(!supports_blending) return internal_masks;
1217 if(IS_NULL_PTR(module->blend_params)) return internal_masks;
1218
1219 dt_develop_blend_get_mask_usage(module, module->blend_params, NULL, &raster_used, &drawn_used, &parametric_used);
1220
1221 if(!IS_NULL_PTR(raster)) *raster = raster_used;
1222 if(!IS_NULL_PTR(drawn)) *drawn = drawn_used;
1223 if(!IS_NULL_PTR(parametric)) *parametric = parametric_used;
1224
1225 return raster_used || drawn_used || parametric_used || internal_masks;
1226}
1227
1229{
1230 return dt_iop_module_needs_mask_history_ext(module, NULL, NULL, NULL);
1231}
1232
1233// make sure that blend_params are in sync with the iop struct
1235{
1236 if(module->raster_mask.sink.source)
1237 g_hash_table_remove(module->raster_mask.sink.source->raster_mask.source.users, module);
1238
1239 if(module->blend_params != blendop_params)
1240 memcpy(module->blend_params, blendop_params, sizeof(dt_develop_blend_params_t));
1241
1243 dt_iop_set_mask_mode(module, blendop_params->mask_mode);
1244
1245 // This assumes that the module providing raster mask to the current one is ALWAYS
1246 // MANDATORILY before the current one BOTH in history order AND in pipe order,
1247 // because the current function is run in history order when we load/reload/pop history
1248 if(module->dev)
1249 for(GList *iter = g_list_first(module->dev->iop); iter; iter = g_list_next(iter))
1250 {
1251 dt_iop_module_t *m = (dt_iop_module_t *)iter->data;
1252 if(!strcmp(m->op, blendop_params->raster_mask_source))
1253 {
1254 if(m->multi_priority == blendop_params->raster_mask_instance)
1255 {
1256 g_hash_table_insert(m->raster_mask.source.users, module, GINT_TO_POINTER(blendop_params->raster_mask_id));
1257 dt_print(DT_DEBUG_MASKS, "[raster masks] Committing raster mask from %s (%s) into %s (%s)\n", m->op, m->multi_name, module->op,
1258 module->multi_name);
1259 module->raster_mask.sink.source = m;
1260 module->raster_mask.sink.id = blendop_params->raster_mask_id;
1261 return;
1262 }
1263 }
1264 }
1265 // else if no module->dev, it means we are only loading module's .so
1266
1267 module->raster_mask.sink.source = NULL;
1268 module->raster_mask.sink.id = 0;
1269}
1270
1271gboolean _iop_validate_params(dt_introspection_field_t *field, gpointer params, gboolean report)
1272{
1273 dt_iop_params_t *p = (dt_iop_params_t *)((uint8_t *)params + field->header.offset);
1274
1275 gboolean all_ok = TRUE;
1276
1277 switch(field->header.type)
1278 {
1280 for(int i = 0; i < field->Struct.entries; i++)
1281 {
1282 dt_introspection_field_t *entry = field->Struct.fields[i];
1283
1284 all_ok &= _iop_validate_params(entry, params, report);
1285 }
1286 break;
1288 all_ok = FALSE;
1289 for(int i = field->Union.entries - 1; i >= 0 ; i--)
1290 {
1291 dt_introspection_field_t *entry = field->Union.fields[i];
1292
1293 if(_iop_validate_params(entry, params, report && i == 0))
1294 {
1295 all_ok = TRUE;
1296 break;
1297 }
1298 }
1299 break;
1302 {
1303 if(!memchr(p, '\0', field->Array.count))
1304 {
1305 if(report)
1306 fprintf(stderr, "validation check failed in _iop_validate_params for type \"%s\"; string not null terminated.\n",
1307 field->header.type_name);
1308 all_ok = FALSE;
1309 }
1310 }
1311 else
1312 {
1313 for(int i = 0, item_offset = 0; i < field->Array.count; i++, item_offset += field->Array.field->header.size)
1314 {
1315 if(!_iop_validate_params(field->Array.field, (uint8_t *)params + item_offset, report))
1316 {
1317 if(report)
1318 fprintf(stderr, "validation check failed in _iop_validate_params for type \"%s\", for array element \"%d\"\n",
1319 field->header.type_name, i);
1320 all_ok = FALSE;
1321 break;
1322 }
1323 }
1324 }
1325 break;
1327 all_ok = isnan(*(float*)p) || ((*(float*)p >= field->Float.Min && *(float*)p <= field->Float.Max));
1328 break;
1330 all_ok = (*(int*)p >= field->Int.Min && *(int*)p <= field->Int.Max);
1331 break;
1333 all_ok = (*(unsigned int*)p >= field->UInt.Min && *(unsigned int*)p <= field->UInt.Max);
1334 break;
1336 all_ok = (*(unsigned short int*)p >= field->UShort.Min && *(unsigned short int*)p <= field->UShort.Max);
1337 break;
1339 all_ok = (*(uint8_t*)p >= field->Int8.Min && *(uint8_t*)p <= field->Int8.Max);
1340 break;
1342 all_ok = (*(char*)p >= field->Char.Min && *(char*)p <= field->Char.Max);
1343 break;
1345 all_ok = creal(*(float complex*)p) >= creal(field->FloatComplex.Min) &&
1346 creal(*(float complex*)p) <= creal(field->FloatComplex.Max) &&
1347 cimag(*(float complex*)p) >= cimag(field->FloatComplex.Min) &&
1348 cimag(*(float complex*)p) <= cimag(field->FloatComplex.Max);
1349 break;
1351 all_ok = FALSE;
1352 for(dt_introspection_type_enum_tuple_t *i = field->Enum.values; i && i->name; i++)
1353 {
1354 if(i->value == *(int*)p)
1355 {
1356 all_ok = TRUE;
1357 break;
1358 }
1359 }
1360 break;
1362 // *(gboolean*)p
1363 break;
1365 // TODO: special case float2
1366 break;
1367 default:
1368 fprintf(stderr, "unsupported introspection type \"%s\" encountered in _iop_validate_params (field %s)\n",
1369 field->header.type_name, field->header.name);
1370 all_ok = FALSE;
1371 break;
1372 }
1373
1374 if(!all_ok && report)
1375 fprintf(stderr, "validation check failed in _iop_validate_params for type \"%s\"%s%s\n",
1376 field->header.type_name, (*field->header.name ? ", field: " : ""), field->header.name);
1377
1378 return all_ok;
1379}
1380
1381
1383{
1384 // Use module fingerprints to determine if two instances are actually the same
1385 return mod_1 == mod_2
1386 && mod_1->instance == mod_2->instance
1387 && mod_1->multi_priority == mod_2->multi_priority
1388 && mod_1->iop_order == mod_2->iop_order;
1389}
1390
1391
1392void _hash_raster_masks(gpointer key, gpointer value, uint64_t *hash)
1393{
1394 dt_iop_module_t *module = (dt_iop_module_t *)key;
1395
1396 // Use only "constant" module params with regard to the pipeline
1397 // init/resync aka we can't use any module pre-computed hash.
1398 // Not module->instance, for the reason dt_iop_compute_module_hash() gives: it is renumbered on
1399 // every darkroom entry, and op, iop_order and multi_priority already name the provider.
1400 *hash = dt_hash(*hash, (char *)module->op, sizeof(module->op));
1401 *hash = dt_hash(*hash, (char *)&module->iop_order, sizeof(module->iop_order));
1402 *hash = dt_hash(*hash, (char *)&module->multi_priority, sizeof(module->multi_priority));
1403 *hash = dt_hash(*hash, (char *)module->blend_params, sizeof(dt_develop_blend_params_t));
1404}
1405
1406
1408{
1409 // Blend params are always inited even when module doesn't support blending
1410 hash = dt_hash(hash, (char *)module->blend_params, sizeof(dt_develop_blend_params_t));
1411
1412 if(module->flags() & IOP_FLAGS_SUPPORTS_BLENDING)
1413 {
1414 // The caller owns the choice of forms list: the commit path passes the live dev->forms
1415 // (dt_dev_history_item_update_from_params falls back to it when no snapshot was taken, so
1416 // the hash of a module whose blend params reference a mask group can never come out blind
1417 // to that group's content — issue #1060 family), while history replay passes the snapshot
1418 // accumulated at the item's own position. NO ambient fallback here: this function cannot
1419 // know whether live forms describe the state being hashed (they don't during replay,
1420 // where dev->forms still holds the state being left).
1421 if(!IS_NULL_PTR(masks))
1422 {
1424 hash = dt_masks_group_get_hash_ext(hash, masks, grp);
1425 }
1426
1427 // else : no module->dev when running from init_default_params()
1428
1429 // If module PROVIDES raster masks to others later in the pipe:
1430 // Account for later modules that reuse the raster mask provided by the current module.
1431 // This is a little cache invalidation trick: we change the final piece hash of this module,
1432 // to signal to the pipeline that it needs to recompute from lower than just the last changed module,
1433 // if that module references the raster mask produced here.
1434 // This contains the list of consumer modules:
1435 g_hash_table_foreach(module->raster_mask.source.users, (GHFunc)_hash_raster_masks, (gpointer)&hash);
1436
1437 // module->raster_mask.source.masks contains only one mask as of now,
1438 // aka its blendop output, so no need to iterate over that.
1439
1440 // If module CONSUMES raster masks from a module earlier in the pipe:
1441 // Account for its blendops.
1442 dt_iop_module_t *raster_source = module->raster_mask.sink.source;
1443 if(raster_source)
1444 {
1445 // Drawn masks
1446 if(!IS_NULL_PTR(masks))
1447 {
1448 dt_masks_form_t *raster_grp = dt_masks_get_from_id_ext(masks, raster_source->blend_params->mask_id);
1449 hash = dt_masks_group_get_hash_ext(hash, masks, raster_grp);
1450 }
1451
1452 // Blending
1453 hash = dt_hash(hash, (char *)raster_source->blend_params, sizeof(dt_develop_blend_params_t));
1454 }
1455 }
1456
1457 module->blendop_hash = hash;
1458}
1459
1460
1462{
1463 // Uniform way of getting the full state hash of user-defined parameters,
1464 // including masks and blending.
1465 // WARNING: doesn't take into account parameters dynamically set at runtime.
1466
1467 /* NOT module->instance. That is a runtime identity -- the family id dt_dev_module_duplicate()
1468 * matches on -- handed out by a counter on the dev that is never reset, so every darkroom
1469 * entry, which reloads the modules into the same dev, numbers them anew. Folding it here rekeyed
1470 * every cacheline of the image on each re-entry and the pipe recomputed from basebuffer although
1471 * its whole cache was still there. op, multi_priority and iop_order already tell every piece of
1472 * the pipe apart; what identifies a piece's output must be what the piece computes. */
1473 uint64_t hash = dt_hash(5381, (char *)module->op, sizeof(dt_dev_operation_t));
1474 hash = dt_hash(hash, (char *)&module->enabled, sizeof(gboolean));
1475 hash = dt_hash(hash, (char *)&module->multi_priority, sizeof(int));
1476 hash = dt_hash(hash, (char *)&module->iop_order, sizeof(int));
1477
1478 // Compute stand-alone blendop hash (mask hash) from the above
1479 // save to module->blendop_hash
1480 dt_iop_compute_blendop_hash(module, hash, masks);
1481
1482 // Finish our module-wide (output) hash
1483 hash = dt_hash(hash, (char *)module->params, module->params_size);
1484 hash = dt_hash(hash, (char *)&module->blendop_hash, sizeof(uint64_t));
1485
1486 module->hash = hash;
1487}
1488
1516{
1517 if(IS_NULL_PTR(piece)) return FALSE;
1518
1519 if(IS_NULL_PTR(module))
1520 {
1521 dt_print(DT_DEBUG_ALWAYS, "[dt_iop_commit_params] missing module, skipping commit\n");
1522 return FALSE;
1523 }
1524
1525 if(IS_NULL_PTR(pipe))
1526 {
1527 dt_print(DT_DEBUG_ALWAYS, "[dt_iop_commit_params] missing pipe for `%s', skipping commit\n",
1528 module->op);
1529 return FALSE;
1530 }
1531
1532 if(piece->module != module)
1533 {
1535 "[dt_iop_commit_params] node belongs to `%s' but `%s' is committing, skipping\n",
1536 IS_NULL_PTR(piece->module) ? "(none)" : piece->module->op, module->op);
1537 return FALSE;
1538 }
1539
1540 if(IS_NULL_PTR(piece->blendop_data))
1541 {
1543 "[dt_iop_commit_params] `%s' node has no blend storage, skipping commit\n", module->op);
1544 return FALSE;
1545 }
1546
1547 if(piece->data_size > 0 && IS_NULL_PTR(piece->data))
1548 {
1550 "[dt_iop_commit_params] `%s' node claims %" G_GSIZE_FORMAT
1551 " bytes of private data but has none, skipping commit\n", module->op, piece->data_size);
1552 return FALSE;
1553 }
1554
1555 if(IS_NULL_PTR(module->commit_params))
1556 {
1557 dt_print(DT_DEBUG_ALWAYS, "[dt_iop_commit_params] `%s' has no commit_params, skipping\n",
1558 module->op);
1559 return FALSE;
1560 }
1561
1562 return TRUE;
1563}
1564
1566 dt_develop_blend_params_t *blendop_params, dt_dev_pixelpipe_t *pipe,
1568{
1569 /* Before the memcpy below, not after: an untrustworthy node has already been written through
1570 * by the time a callback could reject it. A refused node stays disabled rather than running
1571 * with parameters that were never committed. */
1572 if(!_iop_piece_is_committable(module, pipe, piece))
1573 {
1574 if(!IS_NULL_PTR(piece)) piece->enabled = 0;
1575 return;
1576 }
1577
1578 if(IS_NULL_PTR(params) || IS_NULL_PTR(blendop_params))
1579 {
1580 dt_print(DT_DEBUG_ALWAYS, "[dt_iop_commit_params] `%s' committed with no parameters,"
1581 " skipping\n", module->op);
1582 piece->enabled = 0;
1583 return;
1584 }
1585
1586 // We need to commit also modules that are disabled because some of them
1587 // may self-enabled at commit time, depending on image input.
1588 // 1. commit params
1589 memcpy(piece->blendop_data, blendop_params, sizeof(dt_develop_blend_params_t));
1590
1591#ifdef HAVE_OPENCL
1592 // assume process_cl is ready, commit_params can overwrite this.
1593 if(module->process_cl)
1594 piece->process_cl_ready = 1;
1595
1596 piece->cache_output_on_ram = 0;
1597#endif // HAVE_OPENCL
1598
1599 // register if module allows tiling, commit_params can overwrite this.
1600 if(module->flags() & IOP_FLAGS_ALLOW_TILING)
1601 piece->process_tiling_ready = 1;
1602
1603 if(dt_get_debug_flags() & DT_DEBUG_PARAMS && module->so->get_introspection())
1604 _iop_validate_params(module->so->get_introspection()->field, params, TRUE);
1605
1606 module->commit_params(module, params, pipe, piece);
1607
1608 gchar *string = g_strdup_printf("/plugins/%s/opencl", module->op);
1609
1610 if(!dt_conf_key_exists(string) || !dt_conf_key_not_empty(string))
1611 dt_conf_set_bool(string, TRUE);
1612
1613 piece->process_cl_ready &= dt_conf_get_bool(string);
1614 dt_free(string);
1615
1616 //uint64_t old_hash = module->hash;
1617
1618 // 2. Update the internal hash
1619 // We need to update the blendop params dynamically, because drawn masks (forms)
1620 // belong to pipeline not to modules user params, and raster masks travel through the pipe.
1621 // So, module's blendops depend on the current and whole state of dev->forms if they use them
1622 dt_iop_compute_module_hash(module, module->dev->forms);
1623
1624 uint64_t hash = module->hash;
1625
1626 //if(old_hash != hash)
1627 // fprintf(stdout, "WARNING: hash changed at history -> pipeline commit time for %s\n", module->op);
1628
1629 /* Some modules seal part of their effective runtime contract only in commit_params(),
1630 * after reading GUI-only state, pipe mode, or other non-history inputs. Those modules
1631 * must opt in explicitly, because piece->data may also contain transient pointers or
1632 * scratch state for other modules and therefore cannot be hashed blindly. */
1633 if(module->runtime_data_hash(module, pipe, piece))
1634 {
1635 hash = dt_hash(hash, (const char *)piece->data, piece->data_size);
1636 }
1637
1638 piece->global_hash = piece->hash = hash;
1639 piece->global_mask_hash = piece->blendop_hash = module->blendop_hash;
1640
1641 dt_print(DT_DEBUG_PARAMS, "[pixelpipe] params commit for %s (%s) in pipe %s with hash %" PRIu64 "\n",
1642 module->op, module->multi_name,
1643 dt_pixelpipe_get_pipe_name(pipe->type), piece->hash);
1644}
1645
1647{
1649 if(module->gui_reset && !dt_iop_is_hidden(module)) module->gui_reset(module);
1651}
1652
1653void dt_iop_nap(int32_t usec)
1654{
1655 if(usec <= 0) return;
1656
1657 // relinquish processor
1658 sched_yield();
1659
1660 // additionally wait the given amount of time
1661 g_usleep(usec);
1662}
1663
1665{
1666 return module->bypass_cache;
1667}
1668
1670{
1671 module->bypass_cache = state;
1672
1673 if(state && module->dev)
1674 {
1675 // Disable other modules bypass if set.
1676 for(GList *iop = g_list_last(module->dev->iop);
1677 iop;
1678 iop = g_list_previous(iop))
1679 {
1680 dt_iop_module_t *current = (dt_iop_module_t *)iop->data;
1681 if(current != module && current->bypass_cache) current->bypass_cache = FALSE;
1682 }
1683 }
1684}
1685
1687{
1688 module->bypass_cache_variant = variant;
1689}
1690
1691
1696
1697dt_iop_module_t *dt_iop_get_module_from_list(GList *iop_list, const char *op)
1698{
1699 dt_iop_module_t *result = NULL;
1700
1701 for(GList *modules = iop_list; modules; modules = g_list_next(modules))
1702 {
1703 dt_iop_module_t *mod = (dt_iop_module_t *)modules->data;
1704 if(strcmp(mod->op, op) == 0)
1705 {
1706 result = mod;
1707 break;
1708 }
1709 }
1710
1711 return result;
1712}
1713
1715{
1717}
1718
1719int dt_iop_get_module_flags(const char *op)
1720{
1721 GList *modules = darktable.iop;
1722 while(modules)
1723 {
1724 dt_iop_module_so_t *module = (dt_iop_module_so_t *)modules->data;
1725 if(!strcmp(module->op, op)) return module->flags();
1726 modules = g_list_next(modules);
1727 }
1728 return 0;
1729}
1730
1731// to be called before issuing any query based on memory.darktable_iop_names
1733{
1734 if(IS_NULL_PTR(darktable.iop)) return;
1735
1736 const guint count = g_list_length(darktable.iop);
1737 if(count == 0) return;
1738
1739 // module->name() is the localised display name, which only the module object can give --
1740 // hence the array rather than a table the repository could fill by itself.
1741 dt_iop_name_row_t *rows = (dt_iop_name_row_t *)calloc(count, sizeof(dt_iop_name_row_t));
1742 if(IS_NULL_PTR(rows)) return;
1743
1744 guint i = 0;
1745 for(GList *iop = darktable.iop; iop && i < count; iop = g_list_next(iop))
1746 {
1747 dt_iop_module_so_t *module = (dt_iop_module_so_t *)iop->data;
1748 rows[i].operation = module->op;
1749 rows[i].name = module->name();
1750 i++;
1751 }
1752
1754 dt_free(rows);
1755}
1756
1757const gchar *dt_iop_get_localized_name(const gchar *op)
1758{
1759 // Prepare mapping op -> localized name
1760 static GHashTable *module_names = NULL;
1761 if(IS_NULL_PTR(module_names))
1762 {
1763 module_names = g_hash_table_new(g_str_hash, g_str_equal);
1764 for(GList *iop = darktable.iop; iop; iop = g_list_next(iop))
1765 {
1766 dt_iop_module_so_t *module = (dt_iop_module_so_t *)iop->data;
1767 g_hash_table_insert(module_names, module->op, g_strdup(module->name()));
1768 }
1769 }
1770 if(!IS_NULL_PTR(op))
1771 {
1772 return (gchar *)g_hash_table_lookup(module_names, op);
1773 }
1774 else {
1775 return _("ERROR");
1776 }
1777}
1778
1779const gchar *dt_iop_get_localized_aliases(const gchar *op)
1780{
1781 // Prepare mapping op -> localized name
1782 static GHashTable *module_aliases = NULL;
1783 if(IS_NULL_PTR(module_aliases))
1784 {
1785 module_aliases = g_hash_table_new(g_str_hash, g_str_equal);
1786 for(GList *iop = darktable.iop; iop; iop = g_list_next(iop))
1787 {
1788 dt_iop_module_so_t *module = (dt_iop_module_so_t *)iop->data;
1789 g_hash_table_insert(module_aliases, module->op, g_strdup(module->aliases()));
1790 }
1791 }
1792 if(!IS_NULL_PTR(op))
1793 {
1794 return (gchar *)g_hash_table_lookup(module_aliases, op);
1795 }
1796 else {
1797 return _("ERROR");
1798 }
1799}
1800
1801void dt_iop_update_multi_priority(dt_iop_module_t *module, int new_priority)
1802{
1803 GHashTableIter iter;
1804 gpointer key, value;
1805
1806 g_hash_table_iter_init(&iter, module->raster_mask.source.users);
1807 while(g_hash_table_iter_next(&iter, &key, &value))
1808 {
1809 dt_iop_module_t *sink_module = (dt_iop_module_t *)key;
1810
1811 sink_module->blend_params->raster_mask_instance = new_priority;
1812
1813 // also fix history entries
1814 for(GList *hiter = module->dev->history; hiter; hiter = g_list_next(hiter))
1815 {
1816 dt_dev_history_item_t *hist = (dt_dev_history_item_t *)hiter->data;
1817 if(hist->module == sink_module)
1818 hist->blend_params->raster_mask_instance = new_priority;
1819 }
1820 }
1821
1822 module->multi_priority = new_priority;
1823}
1824
1826{
1827 GHashTableIter iter;
1828 gpointer key, value;
1829
1830 g_hash_table_iter_init(&iter, module->raster_mask.source.users);
1831 while(g_hash_table_iter_next(&iter, &key, &value))
1832 {
1833 if(GPOINTER_TO_INT(value) == id)
1834 return TRUE;
1835 }
1836 return FALSE;
1837}
1838
1839dt_iop_module_t *dt_iop_get_module_by_op_priority(GList *modules, const char *operation, const int multi_priority)
1840{
1841 dt_iop_module_t *mod_ret = NULL;
1842
1843 for(GList *m = modules; m; m = g_list_next(m))
1844 {
1845 dt_iop_module_t *mod = (dt_iop_module_t *)m->data;
1846
1847 if(strcmp(mod->op, operation) == 0
1848 && (mod->multi_priority == multi_priority || multi_priority == -1))
1849 {
1850 mod_ret = mod;
1851 break;
1852 }
1853 }
1854 return mod_ret;
1855}
1856
1857dt_iop_module_t *dt_iop_get_module_by_instance_name(GList *modules, const char *operation, const char *multi_name)
1858{
1859 dt_iop_module_t *mod_ret = NULL;
1860
1861 for(GList *m = modules; m; m = g_list_next(m))
1862 {
1863 dt_iop_module_t *mod = (dt_iop_module_t *)m->data;
1864
1865 if((strcmp(mod->op, operation) == 0)
1866 && ((IS_NULL_PTR(multi_name)) || (strcmp(mod->multi_name, multi_name) == 0)))
1867 {
1868 mod_ret = mod;
1869 break;
1870 }
1871 }
1872 return mod_ret;
1873}
1874
1875gboolean dt_iop_is_first_instance(GList *modules, dt_iop_module_t *module)
1876{
1877 gboolean is_first = TRUE;
1878 GList *iop = modules;
1879 while(iop)
1880 {
1881 dt_iop_module_t *m = (dt_iop_module_t *)iop->data;
1882 if(!strcmp(m->op, module->op))
1883 {
1884 is_first = (m == module);
1885 break;
1886 }
1887 iop = g_list_next(iop);
1888 }
1889
1890 return is_first;
1891}
1892
1893const char **dt_iop_set_description(dt_iop_module_t *module, const char *main_text, const char *purpose, const char *input, const char *process,
1894 const char *output)
1895{
1896 static const char *str_out[5] = {NULL, NULL, NULL, NULL, NULL};
1897
1898 str_out[0] = main_text;
1899 str_out[1] = purpose;
1900 str_out[2] = input;
1901 str_out[3] = process;
1902 str_out[4] = output;
1903
1904 return (const char **)str_out;
1905}
1906
1907// clang-format off
1908// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
1909// vim: shiftwidth=2 expandtab tabstop=2 cindent
1910// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
1911// clang-format on
void dt_gui_refocus_center()
__DT_CLONE_TARGETS__ int process(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, const void *const ivoid, void *const ovoid)
Definition ashift.c:3179
#define TRUE
Definition ashift_lsd.c:162
#define FALSE
Definition ashift_lsd.c:158
#define m
Definition basecurve.c:283
void dt_develop_blend_init_blend_parameters(dt_develop_blend_params_t *blend_params, dt_develop_blend_colorspace_t cst)
Definition blend.c:212
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
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
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
dt_develop_blend_colorspace_t
Definition blend.h:53
@ DEVELOP_BLEND_CS_NONE
Definition blend.h:54
void dt_iop_gui_init_blending(dt_iop_module_t *module)
Definition blend_gui.c:5169
void dt_iop_gui_cleanup_blending(dt_iop_module_t *module)
Definition blend_gui.c:4315
void dt_iop_gui_blending_reload_defaults(dt_iop_module_t *module)
Definition blend_gui.c:4824
The blending panel's GUI state and API, cut out of develop/blend.h.
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
void dt_collection_query_set_iop_names(const dt_iop_name_row_t *rows, const size_t count)
Fill memory.darktable_iop_names, the table the module-name rules join against.
dt_iop_colorspace_type_t
@ IOP_CS_LAB
void dt_conf_set_bool(const char *name, int val)
int dt_conf_get_bool(const char *name)
int dt_conf_key_exists(const char *key)
Does key have a value?
gboolean dt_conf_key_not_empty(const char *name)
struct dt_develop_t * dt_dev_get_global(void)
Definition darktable.c:528
darktable_t darktable
Definition darktable.c:213
struct dt_gui_gtk_t * dt_gui_get_global(void)
Definition darktable.c:523
void dt_database_begin_transaction_batch(void)
Definition database.c:4934
void dt_database_end_transaction_batch(void)
Definition database.c:4956
dt_dev_history_item_t * dt_dev_history_get_last_item_by_module(GList *history_list, dt_iop_module_t *module, int history_end)
Find the last history item referencing a module up to history_end.
#define dt_dev_add_history_item(dev, module, enable, redraw)
int32_t dt_dev_get_history_end_ext(struct dt_develop_t *dev)
Get the current history end index (GUI perspective).
Definition develop.c:1899
void dt_iop_params_t
Definition dev_history.h:43
#define dt_dev_pixelpipe_rebuild_all(dev)
void dt_dev_signal_modules_moved(dt_develop_t *dev)
Definition develop.c:1848
gchar * dt_history_item_get_name(const struct dt_iop_module_t *module)
Definition develop.c:1645
static int dt_pthread_rwlock_unlock(dt_pthread_rwlock_t *rwlock) RELEASE_GENERIC(rwlock) NO_THREAD_SAFETY_ANALYSIS
Definition dtpthread.h:217
static int dt_pthread_rwlock_rdlock(dt_pthread_rwlock_t *rwlock) ACQUIRE_SHARED(rwlock) NO_THREAD_SAFETY_ANALYSIS
Definition dtpthread.h:267
char * dt_exif_xmp_encode(const unsigned char *input, const int len, int *output_len)
Definition exif.cc:2116
What a photograph says about itself: the EXIF, IPTC and XMP tags a camera and a cataloguer write,...
static gboolean dt_iop_colorspace_is_rgb(const dt_iop_colorspace_type_t cst)
Definition format.h:75
gboolean dt_gui_presets_autogen_enabled()
static uint64_t dt_hash(uint64_t hash, const char *str, size_t size)
Definition hash.h:55
static gboolean enable(const dt_image_t *image)
Definition highlights.c:879
char dt_dev_operation_t[20]
The string identifying an operation in the history stack ("exposure", "colorbalancergb",...
Definition history.h:50
int dt_history_repository_find_version_for_params(const char *operation, const void *op_params, const int op_params_size)
The module version some image's history recorded for this exact parameter blob.
uint32_t dt_rawspeed_crop_dcraw_filters(uint32_t filters, uint32_t crop_x, uint32_t crop_y)
static int default_operation_tags(void)
Definition imageop.c:182
dt_iop_module_t * dt_iop_get_module_from_list(GList *iop_list, const char *op)
Definition imageop.c:1697
dt_iop_module_t * dt_iop_get_module(const char *op)
Definition imageop.c:1714
static int default_distort_backtransform(dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, float *points, size_t points_count)
Definition imageop.c:269
void dt_iop_set_darktable_iop_table()
Definition imageop.c:1732
static int _iop_load_module_static(dt_iop_module_so_t *module, const dt_iop_module_static_entry_t *const entry)
Bind one statically-linked IOP module into its dt_iop_module_so_t.
Definition imageop.c:454
gboolean dt_iop_module_needs_mask_history_ext(const dt_iop_module_t *module, gboolean *raster, gboolean *drawn, gboolean *parametric)
Definition imageop.c:1205
static const char * default_aliases(void)
Definition imageop.c:198
static void _init_module_so(void *m)
Definition imageop.c:1031
void dt_iop_load_default_params(dt_iop_module_t *module)
Definition imageop.c:145
static void _iop_ensure_visible(dt_gui_module_t *m)
Definition imageop.c:396
dt_iop_module_t * dt_iop_get_module_by_instance_name(GList *modules, const char *operation, const char *multi_name)
Definition imageop.c:1857
static int default_distort_transform(dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, float *points, size_t points_count)
Definition imageop.c:258
static int default_default_group(void)
Definition imageop.c:170
gboolean dt_iop_is_raster_mask_used(dt_iop_module_t *module, int id)
Definition imageop.c:1825
void dt_iop_commit_params(dt_iop_module_t *module, dt_iop_params_t *params, dt_develop_blend_params_t *blendop_params, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Copy params into the pipeline piece, so the next render uses them.
Definition imageop.c:1565
void dt_iop_compute_module_hash(dt_iop_module_t *module, GList *masks)
Definition imageop.c:1461
void dt_iop_reload_defaults(dt_iop_module_t *module)
Definition imageop.c:792
void _hash_raster_masks(gpointer key, gpointer value, uint64_t *hash)
Definition imageop.c:1392
gboolean dt_iop_module_supports_drawn_mask(dt_iop_module_t *iop)
Definition imageop.c:785
void dt_iop_compute_blendop_hash(dt_iop_module_t *module, uint64_t hash, GList *masks)
Definition imageop.c:1407
void dt_iop_init_pipe(struct dt_iop_module_t *module, struct dt_dev_pixelpipe_t *pipe, struct dt_dev_pixelpipe_iop_t *piece)
Build one pixelpipe node's module-owned storage.
Definition imageop.c:604
gboolean dt_iop_is_first_instance(GList *modules, dt_iop_module_t *module)
Definition imageop.c:1875
static int default_flags(void)
Definition imageop.c:176
void dt_iop_commit_blend_params(dt_iop_module_t *module, const dt_develop_blend_params_t *blendop_params)
Definition imageop.c:1234
uint32_t dt_dev_get_roi_filters(const dt_dev_pixelpipe_iop_t *const piece, const dt_iop_roi_t *const roi_in)
Definition imageop.c:139
void dt_iop_cleanup_module(dt_iop_module_t *module)
Definition imageop.c:1113
static void _iop_modify_roi_out(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe, struct dt_dev_pixelpipe_iop_t *piece, dt_iop_roi_t *roi_out, const dt_iop_roi_t *roi_in)
Definition imageop.c:162
gboolean dt_iop_module_has_raster_mask(const dt_iop_module_t *module)
Definition imageop.c:1194
const gchar * dt_iop_get_localized_aliases(const gchar *op)
Definition imageop.c:1779
const gchar * dt_iop_get_localized_name(const gchar *op)
Definition imageop.c:1757
void dt_iop_set_cache_bypass_variant(dt_iop_module_t *module, int variant)
Definition imageop.c:1686
static void default_commit_params(struct dt_iop_module_t *self, dt_iop_params_t *params, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Definition imageop.c:222
static dt_introspection_field_t * default_get_f(const char *name)
Definition imageop.c:303
int dt_iop_load_module(dt_iop_module_t *module, dt_iop_module_so_t *module_so, dt_develop_t *dev)
Definition imageop.c:1102
gboolean _iop_validate_params(dt_introspection_field_t *field, gpointer params, gboolean report)
Definition imageop.c:1271
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
static void _resolve_presets_blend_colorspace(dt_iop_module_so_t *module_so)
Definition imageop.c:832
static void default_cleanup_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Definition imageop.c:239
static void default_gui_cleanup(dt_iop_module_t *self)
Definition imageop.c:246
void dt_iop_gui_reset(dt_iop_module_t *module)
Definition imageop.c:1646
static void default_init_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Definition imageop.c:231
gboolean dt_iop_module_needs_mask_history(const dt_iop_module_t *module)
Definition imageop.c:1228
void dt_iop_load_modules_so(void)
Definition imageop.c:1073
void dt_iop_nap(int32_t usec)
Definition imageop.c:1653
static void default_cleanup(dt_iop_module_t *module)
Definition imageop.c:251
void dt_iop_default_init(dt_iop_module_t *module)
Definition imageop.c:308
static gboolean _module_carries_history(dt_iop_module_t *module)
Definition imageop.c:760
void dt_iop_unload_modules_so()
Definition imageop.c:1163
static gboolean _iop_piece_is_committable(dt_iop_module_t *module, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Is this pipeline node safe to dispatch module code on?
Definition imageop.c:1514
int default_iop_focus(dt_gui_module_t *m, gboolean toggle)
Definition imageop.c:415
void dt_iop_cleanup_pipe(struct dt_iop_module_t *module, struct dt_dev_pixelpipe_t *pipe, struct dt_dev_pixelpipe_iop_t *piece)
Release module-owned resources for one pixelpipe node.
Definition imageop.c:641
static const char ** default_description(struct dt_iop_module_t *self)
Definition imageop.c:193
gboolean dt_iop_module_is_in_pipeline(dt_iop_module_t *iop)
Definition imageop.c:778
static const char * default_deprecated_msg(void)
Definition imageop.c:203
gboolean dt_iop_is_hidden(dt_iop_module_t *module)
Definition imageop.c:736
static gboolean default_has_defaults(struct dt_iop_module_t *self)
Definition imageop.c:208
const char ** dt_iop_set_description(dt_iop_module_t *module, const char *main_text, const char *purpose, const char *input, const char *process, const char *output)
Definition imageop.c:1893
gboolean dt_iop_so_is_hidden(dt_iop_module_so_t *module)
Definition imageop.c:721
float dt_dev_get_module_scale(const dt_dev_pixelpipe_t *const pipe, const dt_iop_roi_t *const roi_in)
Definition imageop.c:134
int dt_iop_get_module_flags(const char *op)
Definition imageop.c:1719
static gboolean default_runtime_data_hash(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece)
Definition imageop.c:213
gboolean dt_iop_gui_move_module_before(dt_iop_module_t *module, dt_iop_module_t *module_next, const char *reason)
Move a module before another one and commit the GUI-side effects.
Definition imageop.c:707
dt_iop_module_t * dt_iop_get_colorout_module(void)
Definition imageop.c:1692
gboolean dt_iop_check_modules_equal(dt_iop_module_t *mod_1, dt_iop_module_t *mod_2)
Definition imageop.c:1382
static int default_operation_tags_filter(void)
Definition imageop.c:188
gboolean dt_iop_module_instance_exists(dt_iop_module_t *iop)
Definition imageop.c:741
void dt_iop_set_cache_bypass(dt_iop_module_t *module, gboolean state)
Definition imageop.c:1669
static dt_introspection_t * default_get_introspection(void)
Definition imageop.c:295
gboolean dt_iop_get_cache_bypass(dt_iop_module_t *module)
Definition imageop.c:1664
gboolean dt_iop_gui_move_module_after(dt_iop_module_t *module, dt_iop_module_t *module_prev, const char *reason)
Move a module after another one and commit the GUI-side effects.
Definition imageop.c:714
void dt_iop_set_mask_mode(dt_iop_module_t *module, int mask_mode)
Definition imageop.c:1174
static void _iop_modify_roi_in(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe, struct dt_dev_pixelpipe_iop_t *piece, const dt_iop_roi_t *roi_out, dt_iop_roi_t *roi_in)
Definition imageop.c:155
static void _init_presets(dt_iop_module_so_t *module_so)
Definition imageop.c:874
dt_iop_module_t * dt_iop_get_module_by_op_priority(GList *modules, const char *operation, const int multi_priority)
Definition imageop.c:1839
gboolean dt_iop_gui_commit_iop_order_change(dt_develop_t *dev, dt_iop_module_t *module, gboolean enable, gboolean write_history, const char *reason)
Commit the GUI-side consequences of an IOP-order change.
Definition imageop.c:693
static void * default_get_p(const void *param, const char *name)
Definition imageop.c:299
static dt_introspection_field_t * default_get_introspection_linear(void)
Definition imageop.c:291
void dt_iop_update_multi_priority(dt_iop_module_t *module, int new_priority)
Definition imageop.c:1801
static int default_process(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe, const struct dt_dev_pixelpipe_iop_t *piece, const void *const i, void *const o)
Definition imageop.c:281
void dt_iop_gui_cleanup_module(dt_iop_module_t *module)
void dt_iop_gui_init(dt_iop_module_t *module)
const dt_iop_module_static_entry_t dt_iop_static_modules[]
const int dt_iop_static_modules_count
void dt_iop_gui_update_header(dt_iop_module_t *module)
void dt_iop_request_focus(dt_iop_module_t *module)
Move darkroom focus to module, or clear it with NULL.
@ IOP_FLAGS_HIDDEN
Definition imageop.h:189
@ IOP_FLAGS_SUPPORTS_BLENDING
Definition imageop.h:186
@ IOP_FLAGS_ALLOW_TILING
Definition imageop.h:188
@ IOP_FLAGS_NO_MASKS
Definition imageop.h:194
void dt_iop_gui_set_expanded(dt_iop_module_t *module, gboolean expanded, gboolean collapse_others)
@ IOP_GROUP_TECHNICAL
Definition imageop.h:162
#define IOP_GUI_FREE
Definition imageop_gui.h:96
#define DT_INTROSPECTION_VERSION
@ DT_INTROSPECTION_TYPE_BOOL
@ DT_INTROSPECTION_TYPE_ENUM
@ DT_INTROSPECTION_TYPE_OPAQUE
@ DT_INTROSPECTION_TYPE_NONE
@ DT_INTROSPECTION_TYPE_ARRAY
@ DT_INTROSPECTION_TYPE_CHAR
@ DT_INTROSPECTION_TYPE_FLOAT
@ DT_INTROSPECTION_TYPE_UNION
@ DT_INTROSPECTION_TYPE_UINT
@ DT_INTROSPECTION_TYPE_USHORT
@ DT_INTROSPECTION_TYPE_INT8
@ DT_INTROSPECTION_TYPE_STRUCT
@ DT_INTROSPECTION_TYPE_FLOATCOMPLEX
@ DT_INTROSPECTION_TYPE_INT
struct dt_iop_tonecurve_params_t preset
gboolean dt_ioppr_move_iop_after(struct dt_develop_t *dev, dt_iop_module_t *module, dt_iop_module_t *module_prev)
Move a module instance after another module in the pipe.
Definition iop_order.c:2225
gboolean dt_ioppr_move_iop_before(struct dt_develop_t *dev, dt_iop_module_t *module, dt_iop_module_t *module_next)
Move a module instance before another module in the pipe.
Definition iop_order.c:2193
int dt_ioppr_check_iop_order(dt_develop_t *dev, const int32_t imgid, const char *msg)
Debug helper to validate the current order for a develop context.
Definition iop_order.c:2351
@ DT_DEBUG_PARAMS
Definition logging.h:71
@ DT_DEBUG_ALWAYS
Definition logging.h:49
@ 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
#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
uint64_t dt_masks_group_get_hash_ext(uint64_t hash, GList *masks, dt_masks_form_t *form)
Definition masks.c:1401
dt_masks_form_t * dt_masks_get_from_id_ext(GList *forms, int id)
Definition masks.c:899
#define dt_free_align(ptr)
Release memory from dt_alloc_align() and set ptr to NULL.
Definition mem_alloc.h:214
static void * dt_calloc_align(size_t size)
dt_alloc_align() followed by a zero fill.
Definition mem_alloc.h:225
#define dt_free(ptr)
g_free() ptr and set it to NULL, skipping both if it is already NULL.
Definition mem_alloc.h:171
char * key
dt_mipmap_buffer_dsc_flags flags
Definition mipmap_cache.c:4
int dt_opencl_is_inited(void)
Definition opencl.c:3255
const char * name
Definition pdf.h:90
char * dt_pixelpipe_get_pipe_name(dt_dev_pixelpipe_type_t pipe_type)
void dt_module_preset_free(gpointer data)
Release one dt_module_preset_t. Suits g_list_free_full().
GList * dt_preset_repository_list_for_upgrade(const char *operation)
Every preset of operation at any version, with both parameter blobs.
void dt_preset_repository_update_module_params(const char *operation, const char *name, const int op_version, const void *params, const int params_size)
Replace the parameters (and version) of (operation, name).
void dt_preset_repository_set_module_version(const char *operation, const char *name, const int op_version)
Set ONLY the version of (operation, name), leaving the parameters alone.
void dt_preset_repository_set_blend_params(const char *operation, const char *name, const int blendop_version, const void *blend_params, const int blend_params_size)
Replace the blend parameters (and blend version) of (operation, name), at any version....
data.presets: a module's saved parameters, with the conditions under which it auto-applies.
void dt_control_signal_disconnect_all(const struct dt_control_signal_t *ctlsig, gpointer user_data)
Definition signal.c:491
struct dt_control_signal_t * dt_control_signal_get_global(void)
Definition darktable.c:616
static const dt_aligned_pixel_simd_t value
Definition simd.h:144
const float uint32_t state[4]
const float const float param
unsigned __int64 uint64_t
Definition strptime.c:75
GList * iop
Definition darktable.h:177
struct dt_develop_blend_params_t * blend_params
Definition dev_history.h:57
dt_iop_buffer_dsc_t dsc_in
struct dt_iop_module_t *void * data
dt_dev_pixelpipe_type_t type
int32_t gui_attached
Definition develop.h:167
GList * iop
Definition develop.h:269
gboolean update_pending
Definition develop.h:371
GtkWidget * widget
Definition develop.h:367
struct dt_develop_t::@13 color_picker
Authoritative darkroom color-picker state.
dt_pthread_rwlock_t history_mutex
Definition develop.h:247
GList * history
Definition develop.h:259
struct dt_iop_module_t *struct dt_iop_color_picker_t * picker
Definition develop.h:366
gboolean enabled
Definition develop.h:370
GList * forms
Definition develop.h:304
The dt_gui_module_t type is the intersection between a dt_lib_module_t and a dt_iop_module_t structur...
union dt_introspection_field_t * field
dt_introspection_type_t type
dt_introspection_type_enum_tuple_t * values
dt_introspection_type_t type
union dt_introspection_field_t ** fields
union dt_introspection_field_t ** fields
uint32_t filters
Definition format.h:89
dt_iop_module_t * self
Definition imageop.c:129
GtkWidget * header
Definition imageop_gui.h:53
dt_dev_operation_t op
Definition imageop.h:235
One IOP module built into this binary, and the generated function that binds it.
Definition imageop.h:418
void(* fill_so)(dt_iop_module_so_t *module)
Definition imageop.h:420
const char * op
Definition imageop.h:419
dt_iop_params_t * default_params
Definition imageop.h:333
GHashTable * masks
Definition imageop.h:362
struct dt_develop_blend_params_t * blend_params
Definition imageop.h:349
struct dt_iop_module_gui_t * gui
Definition imageop.h:346
char multi_name[128]
Definition imageop.h:387
dt_gui_module_t common_fields
Definition imageop.h:253
struct dt_develop_t * dev
Definition imageop.h:311
uint64_t blendop_hash
Definition imageop.h:404
int32_t instance
Definition imageop.h:266
gboolean bypass_cache
Definition imageop.h:278
gboolean enabled
Definition imageop.h:313
dt_iop_module_so_t * so
Definition imageop.h:376
int(* process_plain)(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe, const struct dt_dev_pixelpipe_iop_t *piece, const void *const i, void *const o)
Definition imageop.h:390
struct dt_iop_module_t::@23::@24 source
struct dt_iop_module_t::@23::@25 sink
GHashTable * users
Definition imageop.h:358
struct dt_develop_blend_params_t * default_blendop_params
Definition imageop.h:349
struct dt_iop_module_t::@23 raster_mask
int32_t params_size
Definition imageop.h:335
uint32_t * histogram
Definition imageop.h:291
dt_dev_operation_t op
Definition imageop.h:259
dt_iop_params_t * params
Definition imageop.h:333
One module's identity, for the rule that searches by module name.
const char * operation
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_introspection_type_float_complex_t FloatComplex
dt_introspection_type_header_t header
dt_introspection_type_ushort_t UShort
dt_introspection_type_float_t Float
dt_introspection_type_union_t Union
dt_introspection_type_uint_t UInt
dt_introspection_type_int_t Int
dt_introspection_type_char_t Char
dt_introspection_type_int8_t Int8
dt_introspection_type_array_t Array
dt_introspection_type_enum_t Enum
dt_introspection_type_struct_t Struct
#define dt_gui_freeze_begin()
#define dt_gui_freeze_end()
#define dt_gui_widget_freeze()