Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
develop.c
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2009-2015, 2018 johannes hanika.
4 Copyright (C) 2010 Alexandre Prokoudine.
5 Copyright (C) 2010-2011 Bruce Guenter.
6 Copyright (C) 2010-2012 Henrik Andersson.
7 Copyright (C) 2011 Karl Mikaelsson.
8 Copyright (C) 2011 Mikko Ruohola.
9 Copyright (C) 2011 Omari Stephens.
10 Copyright (C) 2011 Robert Bieber.
11 Copyright (C) 2011 Rostyslav Pidgornyi.
12 Copyright (C) 2011-2019 Tobias Ellinghaus.
13 Copyright (C) 2012-2014, 2016, 2020-2021 Aldric Renaudin.
14 Copyright (C) 2012 Antony Dovgal.
15 Copyright (C) 2012 Moritz Lipp.
16 Copyright (C) 2012 Richard Wonka.
17 Copyright (C) 2012-2014, 2016-2017 Ulrich Pegelow.
18 Copyright (C) 2013-2022 Pascal Obry.
19 Copyright (C) 2014, 2020 Dan Torop.
20 Copyright (C) 2014 parafin.
21 Copyright (C) 2014-2015 Pedro Côrte-Real.
22 Copyright (C) 2014-2017 Roman Lebedev.
23 Copyright (C) 2016 Alexander V. Smal.
24 Copyright (C) 2017, 2021 luzpaz.
25 Copyright (C) 2018-2019 Edgardo Hoszowski.
26 Copyright (C) 2019 Alexander Blinne.
27 Copyright (C) 2019-2020, 2022-2026 Aurélien PIERRE.
28 Copyright (C) 2019-2021 Diederik Ter Rahe.
29 Copyright (C) 2019-2022 Hanno Schwalm.
30 Copyright (C) 2019 Heiko Bauke.
31 Copyright (C) 2019-2020 Philippe Weyland.
32 Copyright (C) 2020-2021 Chris Elston.
33 Copyright (C) 2020 GrahamByrnes.
34 Copyright (C) 2020 Harold le Clément de Saint-Marcq.
35 Copyright (C) 2020 Hubert Kowalski.
36 Copyright (C) 2020 JP Verrue.
37 Copyright (C) 2020-2021 Ralf Brown.
38 Copyright (C) 2021 paolodepetrillo.
39 Copyright (C) 2021 Sakari Kapanen.
40 Copyright (C) 2022 Martin Bařinka.
41 Copyright (C) 2023 Alynx Zhou.
42 Copyright (C) 2023 lologor.
43 Copyright (C) 2023 Luca Zulberti.
44 Copyright (C) 2023 Ricky Moon.
45 Copyright (C) 2025-2026 Guillaume Stutin.
46
47 darktable is free software: you can redistribute it and/or modify
48 it under the terms of the GNU General Public License as published by
49 the Free Software Foundation, either version 3 of the License, or
50 (at your option) any later version.
51
52 darktable is distributed in the hope that it will be useful,
53 but WITHOUT ANY WARRANTY; without even the implied warranty of
54 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
55 GNU General Public License for more details.
56
57 You should have received a copy of the GNU General Public License
58 along with darktable. If not, see <http://www.gnu.org/licenses/>.
59*/
60#include "common/darktable.h"
61#include <assert.h>
62#include <stddef.h>
63#include <glib/gprintf.h>
64#include <inttypes.h>
65#include <math.h>
66#include <stdint.h>
67#include <stdlib.h>
68#include <string.h>
69#include <strings.h>
70#include <unistd.h>
71
72#include "common/atomic.h"
73#include "common/datetime.h"
74#include "common/debug.h"
75#include "common/history.h"
76#include "common/image_cache.h"
77#include "common/imageio.h"
78#include "common/mipmap_cache.h"
79#include "common/opencl.h"
80#include "common/tags.h"
81#include "control/conf.h"
82#include "control/control.h"
83#include "control/signal.h"
84#include "control/jobs.h"
85#include "develop/blend.h"
86#include "develop/develop.h"
87#include "develop/imageop.h"
88#include "develop/lightroom.h"
89#include "develop/masks.h"
91#include "gui/gtk.h"
92#include "gui/gui_throttle.h"
93#include "gui/presets.h"
94#include "libs/colorpicker.h"
95
96#define DT_IOP_ORDER_INFO (darktable.unmuted & DT_DEBUG_IOPORDER)
97
99{
100 GList *res = NULL;
101 dt_iop_module_t *module;
102 dt_iop_module_so_t *module_so;
103 GList *iop = g_list_first(darktable.iop);
104 while(iop)
105 {
106 module_so = (dt_iop_module_so_t *)iop->data;
107 module = (dt_iop_module_t *)calloc(1, sizeof(dt_iop_module_t));
108 if(dt_iop_load_module_by_so(module, module_so, dev))
109 {
110 dt_free(module);
111 continue;
112 }
113 res = g_list_insert_sorted(res, module, dt_sort_iop_by_order);
114 module->global_data = module_so->data;
115 module->so = module_so;
116 iop = g_list_next(iop);
117 }
118
119 GList *it = res;
120 while(it)
121 {
122 module = (dt_iop_module_t *)it->data;
123 it = g_list_next(it);
124 }
125 return res;
126}
127
128void dt_dev_init(dt_develop_t *dev, int32_t gui_attached)
129{
130 memset(dev, 0, sizeof(dt_develop_t));
135
136 dev->gui_attached = gui_attached;
137 dev->roi.width = -1;
138 dev->roi.height = -1;
139
141
142 if(dev->gui_attached)
143 {
144 dev->pipe = (dt_dev_pixelpipe_t *)malloc(sizeof(dt_dev_pixelpipe_t));
145 dev->preview_pipe = (dt_dev_pixelpipe_t *)malloc(sizeof(dt_dev_pixelpipe_t));
146 // Virtual pipe mirrors preview_pipe for geometry, but is never processed.
147 dev->virtual_pipe = (dt_dev_pixelpipe_t *)malloc(sizeof(dt_dev_pixelpipe_t));
148 dt_dev_pixelpipe_init(dev->pipe, dev);
151 dev->histogram_pre_tonecurve = (uint32_t *)calloc(4 * 256, sizeof(uint32_t));
152 dev->histogram_pre_levels = (uint32_t *)calloc(4 * 256, sizeof(uint32_t));
153
154 // FIXME: these are uint32_t, setting to -1 is confusing
156 dev->histogram_pre_levels_max = -1;
157 }
158
159 dt_dev_set_backbuf(&dev->raw_histogram, 0, 0, 0, -1, -1);
160 dt_dev_set_backbuf(&dev->output_histogram, 0, 0, 0, -1, -1);
161 dt_dev_set_backbuf(&dev->display_histogram, 0, 0, 0, -1, -1);
162
163 dev->proxy.wb_is_D65 = TRUE; // don't display error messages until we know for sure it's FALSE
164 dev->proxy.wb_coeffs[0] = 0.f;
165
166 dev->rawoverexposed.mode = dt_conf_get_int("darkroom/ui/rawoverexposed/mode");
167 dev->rawoverexposed.colorscheme = dt_conf_get_int("darkroom/ui/rawoverexposed/colorscheme");
168 dev->rawoverexposed.threshold = dt_conf_get_float("darkroom/ui/rawoverexposed/threshold");
169
170 dev->overexposed.mode = dt_conf_get_int("darkroom/ui/overexposed/mode");
171 dev->overexposed.colorscheme = dt_conf_get_int("darkroom/ui/overexposed/colorscheme");
172 dev->overexposed.lower = dt_conf_get_float("darkroom/ui/overexposed/lower");
173 dev->overexposed.upper = dt_conf_get_float("darkroom/ui/overexposed/upper");
174
175 if(dev->gui_attached)
176 {
177 dev->color_picker.primary_sample = g_malloc0(sizeof(dt_colorpicker_sample_t));
178 dev->color_picker.display_samples = dt_conf_get_bool("ui_last/colorpicker_display_samples");
180 dev->color_picker.restrict_histogram = dt_conf_get_bool("ui_last/colorpicker_restrict_histogram");
181 }
182
183 dt_dev_reset_roi(dev);
184
185 dev->iop = dt_dev_load_modules(dev);
186}
187
189{
190 if(IS_NULL_PTR(dev)) return;
191 // image_cache does not have to be unref'd, this is done outside develop module.
192
194
195 dev->proxy.chroma_adaptation = NULL;
196 dev->proxy.wb_coeffs[0] = 0.f;
197 if(dev->pipe)
198 {
200 dt_free(dev->pipe);
201 }
202 if(dev->preview_pipe)
203 {
205 dt_free(dev->preview_pipe);
206 }
207 if(dev->virtual_pipe)
208 {
209 // Virtual pipe has nodes and committed params but no pixel buffers.
211 dt_free(dev->virtual_pipe);
212 }
213
215 while(dev->history)
216 {
218 dev->history = g_list_delete_link(dev->history, dev->history);
219 }
222
223 // free pending "before" snapshots for history undo
224 dev->undo_history_depth = 0;
230
231 // free the transient param channel
234 dev->transient_params.params = NULL;
236 dev->transient_params.blend_params = NULL;
237 dev->transient_params.module = NULL;
240
241 while(dev->iop)
242 {
244 dt_free(dev->iop->data);
245 dev->iop = g_list_delete_link(dev->iop, dev->iop);
246 }
247 while(dev->alliop)
248 {
250 dt_free(dev->alliop->data);
251 dev->alliop = g_list_delete_link(dev->alliop, dev->alliop);
252 }
253 g_list_free_full(dev->iop_order_list, dt_free_gpointer);
254 dev->iop_order_list = NULL;
255 while(dev->allprofile_info)
256 {
258 dt_free_align(dev->allprofile_info->data);
259 dev->allprofile_info->data = NULL;
260 dev->allprofile_info = g_list_delete_link(dev->allprofile_info, dev->allprofile_info);
261 }
262
265
267 {
269 dev->color_picker.primary_sample = NULL;
270 }
271
273 g_list_free_full(dev->forms, (void (*)(void *))dt_masks_free_form);
274 dev->forms = NULL;
275 g_list_free_full(dev->allforms, (void (*)(void *))dt_masks_free_form);
276 dev->allforms = NULL;
278
280
281 dt_conf_set_int("darkroom/ui/rawoverexposed/mode", dev->rawoverexposed.mode);
282 dt_conf_set_int("darkroom/ui/rawoverexposed/colorscheme", dev->rawoverexposed.colorscheme);
283 dt_conf_set_float("darkroom/ui/rawoverexposed/threshold", dev->rawoverexposed.threshold);
284
285 dt_conf_set_int("darkroom/ui/overexposed/mode", dev->overexposed.mode);
286 dt_conf_set_int("darkroom/ui/overexposed/colorscheme", dev->overexposed.colorscheme);
287 dt_conf_set_float("darkroom/ui/overexposed/lower", dev->overexposed.lower);
288 dt_conf_set_float("darkroom/ui/overexposed/upper", dev->overexposed.upper);
289}
290
291static gboolean _update_darkroom_roi(dt_develop_t *dev, dt_dev_pixelpipe_t *pipe, int *x, int *y, int *wd, int *ht,
292 float *scale);
293
295{
296 if(IS_NULL_PTR(dev)) return FALSE;
297
298 return dev->image_storage.id > 0
299 && dev->roi.width >= 32
300 && dev->roi.height >= 32
301 && dev->roi.raw_width >= 32
302 && dev->roi.raw_height >= 32
303 && dev->roi.processed_width >= 32
304 && dev->roi.processed_height >= 32
305 && dev->roi.preview_width >= 32
306 && dev->roi.preview_height >= 32;
307}
308
310{
311 if(!dev->roi.raw_inited || !dev->roi.gui_inited) return 1;
312
313 // Keep the virtual pipe synced so ROI computations on the GUI thread
314 // always use up-to-date history and input sizes.
315 if(dev->virtual_pipe->imgid != dev->image_storage.id
316 || dev->virtual_pipe->iwidth != dev->roi.raw_width
317 || dev->virtual_pipe->iheight != dev->roi.raw_height
320 dev->roi.raw_width, dev->roi.raw_height, 1.0f, DT_MIPMAP_FULL);
321
322 if(!dev->virtual_pipe->nodes)
325 {
328 else
330 }
331
334
335 // Compute the virtual full-res output. This needs an inited history
338
339 // Compute the scaling factor that makes full-res output fit within widget
341
342 // The preview backbuffer and the pipeline ROI both live in raster pixels.
343 // `natural_scale` therefore directly maps the processed image size to the
344 // raster backbuffer size, without any GUI-density factor mixed in.
345 // Use roundf() — NOT a plain (int) truncation — so these match the ROI the
346 // worker actually requests in `_update_darkroom_roi()` (which rounds too) and
347 // therefore the size of the backbuffer the pipe produces. A truncation here
348 // disagreed with that rounding by 1px whenever the fractional part was >= 0.5,
349 // which is image-dependent: it silently broke `dt_dev_pixelpipe_has_preview_output()`
350 // (hence ashift structure detection / drawing) on some images but not others,
351 // and resetting the module to neutral did not help because the mismatch does
352 // not depend on the module parameters at all.
353 dev->roi.preview_width = roundf(dev->roi.natural_scale * dev->roi.processed_width);
354 dev->roi.preview_height = roundf(dev->roi.natural_scale * dev->roi.processed_height);
355 dev->roi.output_inited = TRUE;
356
358
360 "[pixelpipe] thumbnail sizes raw %dx%d -> processed %dx%d -> preview %dx%d (scale %.5f)\n",
363
364 return 0;
365}
366
368 const dt_iop_roi_t *roi)
369{
370 if(IS_NULL_PTR(dev) || IS_NULL_PTR(pipe) || !dev->gui_attached || !dev->roi.output_inited) return FALSE;
371
372 int x = 0;
373 int y = 0;
374 int width = 0;
375 int height = 0;
376 float scale = dev->roi.natural_scale;
377
378 if(!IS_NULL_PTR(roi))
379 {
380 x = roi->x;
381 y = roi->y;
382 width = roi->width;
383 height = roi->height;
384 scale = roi->scale;
385 }
386 else
387 {
388 // Recompute the current darkroom output geometry so callers that run ahead of process()
389 // still classify the pipe from the image they are about to produce, not the last backbuffer.
390 _update_darkroom_roi((dt_develop_t *)dev, (dt_dev_pixelpipe_t *)pipe, &x, &y, &width, &height, &scale);
391 }
392
393 // A module upstream of the orientation swap (the "flip" module) — e.g. ashift, demosaic,
394 // highlights — produces output whose width/height are swapped relative to the final, post-flip
395 // preview dimensions on portrait images. Accept that swapped match too: otherwise the
396 // "is this the full preview image?" test wrongly fails for every pre-flip module on portrait,
397 // and `roi` here is the module's own (pre-flip) `roi_out`. This is why ashift never captured its
398 // GUI buffer on portrait images, breaking structure detection and manual drawing (#710).
399 //
400 // Tolerate a couple of pixels of slack on the dimensions. `dev->roi.preview_*` is derived from the
401 // virtual pipe at scale 1.0, whereas `roi` is produced at `natural_scale`; geometric modules
402 // (ashift, lens) round their transformed bounding box with floorf() independently at each scale,
403 // so the two legitimately disagree by ~1px for the very same full image. The real discriminators
404 // are the origin and scale tests below: a zoomed or panned ROI has a non-zero x/y and a scale
405 // strictly greater than natural_scale, so loosening the size match cannot misclassify those.
406 const int tol = 2;
407 const gboolean dims_match
408 = (abs(width - dev->roi.preview_width) <= tol && abs(height - dev->roi.preview_height) <= tol)
409 || (abs(width - dev->roi.preview_height) <= tol && abs(height - dev->roi.preview_width) <= tol);
410 if(!dims_match) return FALSE;
411 return x == 0 && y == 0 && fabsf(scale - dev->roi.natural_scale) < 1e-4f;
412}
413
414
415// Return TRUE if ROI changed since previous computation
416static gboolean _update_darkroom_roi(dt_develop_t *dev, dt_dev_pixelpipe_t *pipe, int *x, int *y, int *wd, int *ht,
417 float *scale)
418{
419 if(!dev->roi.output_inited) return 1;
420
421 // Store previous values
422 int x_old = *x;
423 int y_old = *y;
424 int wd_old = *wd;
425 int ht_old = *ht;
426 float old_scale = *scale;
427
428 // roi->scale is the pipeline sampling ratio against the processed image and
429 // therefore excludes the GUI backing-store density.
430 *scale = dev->roi.natural_scale;
431 const gboolean preview_pipe = (pipe == dev->preview_pipe);
432 if(!preview_pipe) *scale *= dev->roi.scaling;
433
434 // Width, height, x and y are already expressed in raster pixels, so they
435 // must follow the same raster-space sampling ratio as roi->scale.
436 int roi_width = roundf(*scale * dev->roi.processed_width);
437 int roi_height = roundf(*scale * dev->roi.processed_height);
438 int widget_wd = dev->roi.width;
439 int widget_ht = dev->roi.height;
440
441 *wd = roundf(fminf(roi_width, widget_wd));
442 *ht = roundf(fminf(roi_height, widget_ht));
443
444 // dev->roi.x,y are the relative coordinates of the ROI center.
445 // in preview pipe, we always render a full image, so x,y = 0,0
446 // otherwise, x,y here are the top-left corner. Translate:
447 *x = preview_pipe ? 0 : roundf(dev->roi.x * roi_width - *wd * .5f);
448 *y = preview_pipe ? 0 : roundf(dev->roi.y * roi_height - *ht * .5f);
449
450/* fprintf (stderr, "_update_darkroom_roi: dev %.2f %.2f type %s xy %d %d dim %d %d"
451 " ppd:%.4f scale:%.4f nat_scale:%.4f * scaling:%.4f\n",
452 dev->roi.x, dev->roi.y, dt_pipe_type_to_str(pipe->type), *x, *y, *wd, *ht, darktable.gui->ppd, *scale, dev->roi.natural_scale, dev->roi.scaling);
453*/
454 return x_old != *x || y_old != *y || wd_old != *wd || ht_old != *ht || old_scale != *scale;
455}
456
458{
459 if(IS_NULL_PTR(dev) || !dev->gui_attached || IS_NULL_PTR(dev->pipe) || IS_NULL_PTR(dev->preview_pipe) || !dev->roi.output_inited) return FALSE;
460
461 float preview_scale = 1.0f;
462 float main_scale = 1.0f;
463 int preview_x = 0, preview_y = 0, preview_wd = 0, preview_ht = 0;
464 int main_x = 0, main_y = 0, main_wd = 0, main_ht = 0;
465
466 _update_darkroom_roi(dev, dev->preview_pipe, &preview_x, &preview_y, &preview_wd, &preview_ht, &preview_scale);
467 _update_darkroom_roi(dev, dev->pipe, &main_x, &main_y, &main_wd, &main_ht, &main_scale);
468
469 return preview_x == main_x && preview_y == main_y && preview_wd == main_wd && preview_ht == main_ht
470 && fabsf(preview_scale - main_scale) < 1e-4f;
471}
472
473
475{
477 const int32_t imgid = pipe->dev->image_storage.id;
478
479 // Get the mip size that is at most as big as our pipeline backbuf
481
482 // Flush backup to mipmap_cache. This runs after dt_dev_pixelpipe_process() released the OpenCL device
483 // lock, so we must NOT pass pipe->devid (now stale/unlocked): a device-only payload would otherwise be
484 // materialized from the GPU without owning it. The final display backbuffer is always host-resident,
485 // so preferred_devid = -1 returns it directly; anything else is simply skipped.
486 uint8_t *data = NULL;
487 dt_pixel_cache_entry_t *entry = NULL;
488 if(dt_dev_pixelpipe_cache_peek(darktable.pixelpipe_cache, dt_dev_pixelpipe_get_hash(pipe), (void **)&data, &entry, -1, NULL))
489 {
493 }
494}
495
496gboolean _resync_pipe_with_history(dt_develop_t *dev, dt_dev_pixelpipe_t *pipe, dt_iop_roi_t *roi, gboolean *needs_update)
497{
498 // When in realtime mode, preview pipe gets paused at the benefit of main pipeline.
499 // This is a transient state.
500 if(pipe->pause) return FALSE;
501
502 // We recompute if history hash changed or ROI has changed.
503 // If we know history changed, ensure at least the last step is resynced.
504 const uint64_t pipe_hash = dt_dev_pixelpipe_get_history_hash(pipe);
505 const uint64_t dev_hash = dt_dev_get_history_hash(dev);
506 if(pipe_hash != dev_hash)
507 {
509 dt_print(DT_DEBUG_PIPE | DT_DEBUG_DEV, "dev history hash = %" PRIu64 ", pipe history hash %" PRIu64 "\n", dev_hash, pipe_hash);
510 }
511
512 *needs_update = (dt_dev_pixelpipe_get_changed(pipe) != DT_DEV_PIPE_UNCHANGED);
513 if(!*needs_update) return FALSE;
514
516 pipe->processing = 1;
517
518 // Commit history to pipeline.
519 // This can take 40-80 ms or much more with masks on weak hardware,
520 // so user may have changed the history again during that lapse.
521 gboolean pipe_resynced = FALSE;
523 {
525 pipe_resynced = TRUE;
526 }
527
528 // Plan the ROI for this run and finalize the cumulative global hash now, while the pipe is
529 // settled and not yet publishing pixels. dt_dev_pixelpipe_process() recomputes both at its
530 // entry (it is also called directly by export/snapshot pipes), but computing them here is
531 // what lets the HISTORY_RESYNC signal below advertise a hash that is already final.
532 int x = 0, y = 0, wd = 0, ht = 0;
533 float scale = 1.f;
534 _update_darkroom_roi(dev, pipe, &x, &y, &wd, &ht, &scale);
535 *roi = (dt_iop_roi_t){ x, y, wd, ht, scale };
536 dt_dev_pixelpipe_get_roi_in(pipe, *roi);
538
539 pipe->processing = 0;
541
542 return pipe_resynced;
543}
544
545
558{
559 dt_dev_pixelpipe_t *const pipes[] = { dev->preview_pipe, dev->pipe };
560
561 for(size_t i = 0; i < G_N_ELEMENTS(pipes); i++)
562 pipes[i]->running = 1;
563
564 // Infinite loop: run for as long as the worker thread is running.
565 while(!dev->exit && dt_control_running())
566 {
568 {
569 dt_iop_nap(50000); // wait 50 ms until GUI/image sizes are initialized
570 continue;
571 }
572
573 // This is cheap to run, keep it in sync always.
574 for(size_t i = 0; i < G_N_ELEMENTS(pipes); i++)
576 1.0f, DT_MIPMAP_FULL);
577
578 gboolean pipe_needs_update[G_N_ELEMENTS(pipes)] = { FALSE };
579 dt_iop_roi_t pipe_roi[G_N_ELEMENTS(pipes)] = { { 0 } };
580 gboolean history_resynced = FALSE;
581
582 // First, resynchronize all dirty pipelines from history, plan their ROI and finalize their
583 // cumulative global hash, so GUI listeners can resolve stable piece->global_hash values
584 // before any cacheline starts publishing pixels.
585 for(size_t i = 0; i < G_N_ELEMENTS(pipes); i++)
586 history_resynced |= _resync_pipe_with_history(dev, pipes[i], &pipe_roi[i], &pipe_needs_update[i]);
587
588 // NOTE: at this point, we fully know the state of __all__ our GUI pipelines :
589 // - global image input and output size,
590 // - per-module input and output size,
591 // - per-module input and output format (channels, bit depth, mosaiced/raster, CFA pattern)
592 // - pipeline nodes (modules) params are up-to-to date with history,
593 // - global_hash of each module is and stable until next history resync,
594 // - modules whose expected input format is incompatible with previous module output format
595 // will have been disabled from pipeline, but not from history, aka we know our pipelines
596 // can run start to end.
597
598 // GUI widgets that need an image buffer will connect to this signal to grab
599 // the global_hash of the module they are waiting for, even though it's still not ready.
600 if(history_resynced)
602
603 // Second, compute pipelines.
604 // Always service preview first, then the main pipe, so the main pipe can reuse the cache state
605 // just published by preview instead of trying to race it from another thread.
606 for(size_t i = 0; i < G_N_ELEMENTS(pipes) && dt_control_running() && !dev->exit; i++)
607 {
608 if(!pipe_needs_update[i]) continue;
609
610 dt_dev_pixelpipe_t *pipe = pipes[i];
611 const dt_iop_roi_t roi = pipe_roi[i];
612
613 // The resync stage above synchronized history, planned the ROI and advertised the matching
614 // final global hash. We process the exact state it committed, using pipe_roi[i]: that is what
615 // dt_dev_pixelpipe_process() recomputes its hash from, so the cacheline it publishes always
616 // carries the hash already announced to GUI consumers. A change that landed after the resync
617 // (zoom/pan, a fresh history commit) does NOT invalidate this run — it always also raised the
618 // killswitch (`_change_pipe()` sets shutdown together with the changed flag), so the run below
619 // aborts cleanly and the next loop iteration resyncs, re-advertises and reprocesses the new
620 // state. We must NOT skip on a set changed flag here: every darkroom configure-event flags the
621 // preview pipe ZOOMED, so on an image switch (which re-lays-out the view) skipping would starve
622 // the preview and leave navigation/scopes blank.
623 dt_print(DT_DEBUG_PIPE | DT_DEBUG_DEV, "PIPE %s needs update\n", pipe->type == DT_DEV_PIXELPIPE_FULL ? "full" : "preview");
624
626 pipe->processing = 1;
627
628 // We are starting fresh, reset the killswitch signal.
630
638 const gboolean retrying_raster_mask = dt_dev_pixelpipe_has_reentry(pipe);
639
640 // Whether the recompute was triggered because we needed only the output of
641 // a specified module, or we needed the output backbuf of the whole pipeline.
642 // This allows partial pipeline runs, e.g. for histograms and color-pickers.
644
645 // At zoom == fit, both preview and main pipelines have the same size,
646 // so the first one that runs will prevent the next from running
647 // (backbuf fetched directly from pipeline cache).
648 // Therefore we can't rely solely on pipeline type to raise completion signals.
649 const gboolean has_preview_size = dt_dev_pixelpipe_has_preview_output(dev, pipe, &roi);
650
656 const gboolean requested_mask_preview
657 = pipe == dev->pipe
658 && !IS_NULL_PTR(dev->gui_module)
660
661 // Connect GUI feedback for "pipe busy"
664 dev->progress.completed = 0;
665 dev->progress.total = 0;
666
667 dt_times_t thread_start;
668 dt_get_times(&thread_start);
669
670 // The actual processing with runtime log
671 const gint64 process_start_us = g_get_monotonic_time();
672 const int ret = dt_dev_pixelpipe_process(pipe, roi);
673 const gint64 process_runtime_us = g_get_monotonic_time() - process_start_us;
674
675 // Print perf log
676 gchar *msg = g_strdup_printf("[dev_process_%s] pipeline processing thread",
678 dt_show_times(&thread_start, msg);
679 dt_free(msg);
680
681 // Disconnect GUI feedback for "pipe busy"
682 dev->progress.completed = 0;
683 dev->progress.total = 0;
686
687 // Pipeline completed entirely without error
688 const gboolean processed = (!ret && !dt_atomic_get_int(&pipe->shutdown));
689
697 const gboolean published_backbuffer
698 = processed && dt_dev_pixelpipe_is_backbufer_valid(pipe);
699
700 // Pipeline reentry flag is set when we lost the reference to a raster mask.
701 // This typically happens on re-entering darkroom after having gone to lighttable:
702 // the pipeline cache is kept but the references to raster masks are flushed,
703 // so the pipeline recomputation resumes downstream from the last-known cacheline,
704 // which may not refresh raster masks if produced upstream in pipeline.
705 // TODO: cache raster masks too (was attempted before, and failed).
707 {
708 if(retrying_raster_mask)
709 {
710 // Reentry flag was set already before last pipe run, which refreshed
711 // everything we needed. We can resume to normal mode.
712 // In case that wasn't true, it will be caught at the next run.
714 }
715 else
716 {
717 // Reentry flag was set during the last pipe run, which means we
718 // lost at least a raster mask reference, and need to retry again
719 // from the start.
720 // The synchronized graph and its ROIs are still valid. The retry
721 // only needs another processing pass after targeted cache
722 // invalidation, not node destruction and history reconstruction.
724 }
725 }
726
735 if(processed
736 && cache_request == DT_DEV_PIXELPIPE_CACHE_REQUEST_MODULE
737 && !published_backbuffer)
738 {
742 }
743
744 pipe->processing = 0;
746
747 // Update the running average of process time for GUI controls thresholding
748 if(processed)
749 dt_gui_throttle_record_runtime(pipe, process_runtime_us);
750
751 // If everything went well, yell to GUI listeners that they can use the output buffer.
752 if(published_backbuffer)
753 {
754 if(pipe->type == DT_DEV_PIXELPIPE_FULL)
755 {
758 }
759 if(pipe->type == DT_DEV_PIXELPIPE_PREVIEW || has_preview_size)
760 {
763 }
764
776 && has_preview_size
777 && !requested_mask_preview
779 dt_dev_resync_mipmap_cache(dev, pipe, roi);
780 }
781
782 // Allow some breathing room to the OS and GPU
783 dt_iop_nap(10000); // 10 ms
784 }
785
787 dt_iop_nap(10000);
788 else
789 dt_iop_nap(50000);
790 }
791
792 for(size_t i = 0; i < G_N_ELEMENTS(pipes); i++)
793 pipes[i]->running = 0;
794}
795
797{
800 return 0;
801}
802
804{
805 dt_job_t *job = dt_control_job_create(&dt_dev_process_job_run, "develop process image");
806 if(IS_NULL_PTR(job)) return NULL;
807 dt_control_job_set_params(job, dev, NULL);
808 return job;
809}
810
817
818static gboolean _dt_dev_mipmap_prefetch_full(dt_develop_t *dev, const int32_t imgid)
819{
822
823 const gboolean ok = (!IS_NULL_PTR(buf.buf)) && buf.width != 0 && buf.height != 0;
824
825 if(dev->gui_attached)
826 {
827 dev->roi.raw_height = buf.height;
828 dev->roi.raw_width = buf.width;
829 dev->roi.raw_inited = TRUE;
830 }
831
833
834 return ok;
835}
836
837static gboolean _dt_dev_refresh_image_storage(dt_develop_t *dev, const int32_t imgid)
838{
839 const dt_image_t *image = dt_image_cache_get(darktable.image_cache, imgid, 'r');
840 if(IS_NULL_PTR(image)) return FALSE;
841 dev->image_storage = *image;
844 return TRUE;
845}
846
860
861// load the raw and get the new image struct, blocking in gui thread
862static inline dt_dev_image_storage_t _dt_dev_load_raw(dt_develop_t *dev, const int32_t imgid)
863{
864 // then load the raw
865 dt_times_t start;
866 dt_get_times(&start);
867
868 // Test we got images. Also that populates the cache for later.
869 // Refresh our private copy in case raw loading updated image metadata
870 const dt_dev_image_storage_t storage_status = dt_dev_ensure_image_storage(dev, imgid);
871 if(storage_status)
872 return storage_status;
873
874 dt_show_times_f(&start, "[dev_pixelpipe]", "to load the image.");
875
876 return storage_status;
877}
878
879// return the zoom scale to fit into the viewport
880float dt_dev_get_zoom_scale(const dt_develop_t *dev, const gboolean preview)
881{
882 const float w = preview ? dev->roi.processed_width : dev->pipe->processed_width;
883 const float h = preview ? dev->roi.processed_height : dev->pipe->processed_height;
884 return fminf(dev->roi.width / w, dev->roi.height / h);
885}
886
888{
889 const dt_dev_image_storage_t ret = _dt_dev_load_raw(dev, imgid);
890 if(ret) return ret;
891
892 // we need a global lock as the dev->iop set must not be changed until read history is terminated
894
895 const gboolean first_run = dt_dev_read_history_ext(dev, imgid);
896
897 if(first_run && dev == darktable.develop)
898 {
899 // Resync our private copy of image image with DB,
900 // mostly for DT_IMAGE_AUTO_PRESETS_APPLIED flag.
902 if(!IS_NULL_PTR(image))
903 {
904 *image = dev->image_storage;
906 }
907
908 dt_dev_write_history_ext(dev, imgid);
909 }
910
912
913 if(first_run && dev == darktable.develop)
914 {
917 }
918
919 return ret;
920}
921
922void dt_dev_configure_real(dt_develop_t *dev, int wd, int ht)
923{
924 // Called only from Darkroom to convert the widget allocation into the
925 // raster ROI contract consumed by the pipeline. Everything stored in
926 // dev->roi below is expressed in real buffer pixels.
927 const dt_iop_roi_t gui_roi = { .x = 0, .y = 0, .width = wd, .height = ht, .scale = 1.0f };
928 dt_iop_roi_t pipe_roi = { 0 };
930 dev->roi.width = pipe_roi.width;
931 dev->roi.height = pipe_roi.height;
932 dev->roi.gui_inited = TRUE;
933
935 "[pixelpipe] Darkroom requested a %i×%i px widget -> %i×%i px raster preview\n",
936 wd, ht, dev->roi.width, dev->roi.height);
937
942}
943
944void dt_dev_check_zoom_pos_bounds(dt_develop_t *dev, float *dev_x, float *dev_y, float *box_w, float *box_h)
945{
946 // for the debug strings lower
947 //float old_x = *dev_x;
948 //float old_y = *dev_y;
949 int proc_w = 0;
950 int proc_h = 0;
951 dt_dev_get_processed_size(dev, &proc_w, &proc_h);
952 const float scale = dt_dev_get_zoom_level(dev);
953
954 // find the box size
955 const float bw = dev->roi.width / (proc_w * scale);
956 const float bh = dev->roi.height / (proc_h * scale);
957
958 // calculate half-dimensions once
959 const float half_bw = bw * 0.5f;
960 const float half_bh = bh * 0.5f;
961
962 // clamp position using pre-calculated values
963 *dev_x = (bw > 1.0f || dev->roi.scaling <= 1.0f) ? 0.5f : CLAMPF(*dev_x, half_bw, 1.0f - half_bw);
964 *dev_y = (bh > 1.0f || dev->roi.scaling <= 1.0f) ? 0.5f : CLAMPF(*dev_y, half_bh, 1.0f - half_bh);
965 // return box size
966 if(!IS_NULL_PTR(box_w)) *box_w = bw;
967 if(!IS_NULL_PTR(box_h)) *box_h = bh;
968
969 /*
970 fprintf(stdout, "BOUNDS: box size: %2.2f x %2.2f\n", bw, bh);
971 fprintf(stdout, "BOUNDS: half box size: %2.2f x %2.2f\n", half_bw, half_bh);
972 fprintf(stdout, "BOUNDS: X pos: %2.2f -> %2.2f [%2.2f %2.2f]\n",
973 old_x, *dev_x, half_bw, 1.0f - half_bw);
974 fprintf(stdout, "BOUNDS: Y pos: %2.2f -> %2.2f [%2.2f %2.2f]\n",
975 old_y, *dev_y, half_bh, 1.0f - half_bh);
976*/
977}
978
979void dt_dev_get_processed_size(const dt_develop_t *dev, int *procw, int *proch)
980{
981 if(IS_NULL_PTR(dev)) return;
982 *procw = dev->roi.processed_width;
983 *proch = dev->roi.processed_height;
984 }
985
986void dt_dev_coordinates_widget_delta_to_image_delta(dt_develop_t *dev, float *points, size_t num_points)
987{
988 if(IS_NULL_PTR(dev) || IS_NULL_PTR(points) || num_points == 0) return;
989
990 const float scale = dt_dev_get_zoom_level(dev) / darktable.gui->ppd;
991 if(scale == 0.0f) return;
992
993 // Widget deltas are measured in Gtk logical pixels. Convert them to processed-image
994 // pixels here so dragging thresholds and keyboard pans share the same zoom math.
995 for(size_t i = 0; i < num_points; ++i)
996 {
997 const size_t idx = i * 2;
998 points[idx + 0] /= scale;
999 points[idx + 1] /= scale;
1000 }
1001}
1002
1003void dt_dev_coordinates_widget_to_image_norm(dt_develop_t *dev, float *points, size_t num_points)
1004{
1005 if(IS_NULL_PTR(dev) || IS_NULL_PTR(points) || num_points == 0) return;
1006 const float processed_width = dev->roi.processed_width;
1007 const float processed_height = dev->roi.processed_height;
1008 if(processed_width == 0.0f || processed_height == 0.0f) return;
1009
1010 // Widget events are expressed in GUI logical coordinates, while the pipeline
1011 // zoom lives in raster pixels. Convert back to the same GUI-space zoom used
1012 // by dt_dev_rescale_roi() so event hit-testing and overlay drawing stay aligned.
1013 const float scale = dt_dev_get_zoom_level(dev) / darktable.gui->ppd;
1014 const float roi_x = (float)dev->roi.x;
1015 const float roi_y = (float)dev->roi.y;
1016 const float center_x = 0.5f * (float)dev->roi.orig_width;
1017 const float center_y = 0.5f * (float)dev->roi.orig_height;
1018 const float inv_scaled_width = 1.0f / (processed_width * scale);
1019 const float inv_scaled_height = 1.0f / (processed_height * scale);
1020
1021 for(size_t i = 0; i < num_points; ++i)
1022 {
1023 const size_t idx = i * 2;
1024 const float px = points[idx + 0];
1025 const float py = points[idx + 1];
1026 points[idx + 0] = roi_x + (px - center_x) * inv_scaled_width;
1027 points[idx + 1] = roi_y + (py - center_y) * inv_scaled_height;
1028 }
1029}
1030
1031void dt_dev_coordinates_image_norm_to_widget(dt_develop_t *dev, float *points, size_t num_points)
1032{
1033 if(IS_NULL_PTR(dev) || IS_NULL_PTR(points) || num_points == 0) return;
1034 const float processed_width = dev->roi.processed_width;
1035 const float processed_height = dev->roi.processed_height;
1036 if(processed_width == 0.0f || processed_height == 0.0f) return;
1037
1038 // GUI overlays are drawn in logical widget coordinates, so use the same
1039 // GUI-space zoom that the Cairo darkroom transform applies.
1040 const float scale = dt_dev_get_zoom_level(dev) / darktable.gui->ppd;
1041 const float roi_x = (float)dev->roi.x;
1042 const float roi_y = (float)dev->roi.y;
1043 const float scaled_width = processed_width * scale;
1044 const float scaled_height = processed_height * scale;
1045 const float center_x = 0.5f * (float)dev->roi.orig_width;
1046 const float center_y = 0.5f * (float)dev->roi.orig_height;
1047
1048 for(size_t i = 0; i < num_points; ++i)
1049 {
1050 const size_t idx = i * 2;
1051 const float px = points[idx + 0];
1052 const float py = points[idx + 1];
1053 const float dx = (px - roi_x) * scaled_width;
1054 const float dy = (py - roi_y) * scaled_height;
1055 points[idx + 0] = dx + center_x;
1056 points[idx + 1] = dy + center_y;
1057 }
1058}
1059
1060void dt_dev_coordinates_image_norm_to_image_abs(dt_develop_t *dev, float *points, size_t num_points)
1061{
1062 if(IS_NULL_PTR(dev) || IS_NULL_PTR(points) || num_points == 0) return;
1063 const float processed_width = dev->roi.processed_width;
1064 const float processed_height = dev->roi.processed_height;
1065 if(processed_width == 0.0f || processed_height == 0.0f) return;
1066
1067 for(size_t i = 0; i < num_points; ++i)
1068 {
1069 const size_t idx = i * 2;
1070 points[idx + 0] *= processed_width;
1071 points[idx + 1] *= processed_height;
1072 }
1073}
1074
1075void dt_dev_coordinates_image_abs_to_image_norm(dt_develop_t *dev, float *points, size_t num_points)
1076{
1077 if(IS_NULL_PTR(dev) || IS_NULL_PTR(points) || num_points == 0) return;
1078 const float processed_width = dev->roi.processed_width;
1079 const float processed_height = dev->roi.processed_height;
1080 if(processed_width == 0.0f || processed_height == 0.0f) return;
1081
1082 const float inv_width = 1.0f / processed_width;
1083 const float inv_height = 1.0f / processed_height;
1084 for(size_t i = 0; i < num_points; ++i)
1085 {
1086 const size_t idx = i * 2;
1087 points[idx + 0] *= inv_width;
1088 points[idx + 1] *= inv_height;
1089 }
1090}
1091
1092void dt_dev_coordinates_raw_abs_to_raw_norm(dt_develop_t *dev, float *points, size_t num_points)
1093{
1094 if(IS_NULL_PTR(dev) || IS_NULL_PTR(points) || num_points == 0) return;
1095 const float raw_width = dev->roi.raw_width;
1096 const float raw_height = dev->roi.raw_height;
1097 if(raw_width == 0.0f || raw_height == 0.0f) return;
1098
1099 const float inv_width = 1.f / raw_width;
1100 const float inv_height = 1.f / raw_height;
1101 for(size_t i = 0; i < num_points; i++)
1102 {
1103 const size_t idx = i * 2;
1104 points[idx + 0] *= inv_width;
1105 points[idx + 1] *= inv_height;
1106 }
1107}
1108
1109void dt_dev_coordinates_raw_norm_to_raw_abs(dt_develop_t *dev, float *points, size_t num_points)
1110{
1111 if(IS_NULL_PTR(dev) || IS_NULL_PTR(points) || num_points == 0) return;
1112 const float raw_width = dev->roi.raw_width;
1113 const float raw_height = dev->roi.raw_height;
1114 if(raw_width == 0.0f || raw_height == 0.0f) return;
1115
1116 for(size_t i = 0; i < num_points; i++)
1117 {
1118 const size_t idx = i * 2;
1119 points[idx + 0] *= raw_width;
1120 points[idx + 1] *= raw_height;
1121 }
1122}
1123
1124void dt_dev_coordinates_image_norm_to_raw_norm(dt_develop_t *dev, float *points, size_t num_points)
1125{
1126 dt_dev_coordinates_image_norm_to_image_abs(dev, points, num_points);
1127 dt_dev_coordinates_image_abs_to_raw_abs(dev, points, num_points);
1128 dt_dev_coordinates_raw_abs_to_raw_norm(dev, points, num_points);
1129}
1130
1131void dt_dev_coordinates_raw_norm_to_image_norm(dt_develop_t *dev, float *points, size_t num_points)
1132{
1133 dt_dev_coordinates_raw_norm_to_raw_abs(dev, points, num_points);
1134 dt_dev_coordinates_raw_abs_to_image_abs(dev, points, num_points);
1135 dt_dev_coordinates_image_abs_to_image_norm(dev, points, num_points);
1136}
1137
1138void dt_dev_coordinates_image_abs_to_raw_norm(dt_develop_t *dev, float *points, size_t num_points)
1139{
1140 dt_dev_coordinates_image_abs_to_raw_abs(dev, points, num_points);
1141 dt_dev_coordinates_raw_abs_to_raw_norm(dev, points, num_points);
1142}
1143
1144void dt_dev_coordinates_image_norm_to_preview_abs(dt_develop_t *dev, float *points, size_t num_points)
1145{
1146 if(IS_NULL_PTR(dev) || IS_NULL_PTR(points) || num_points == 0) return;
1147 const float preview_width = dev->roi.preview_width;
1148 const float preview_height = dev->roi.preview_height;
1149 if(preview_width == 0.0f || preview_height == 0.0f) return;
1150
1151 for(size_t i = 0; i < num_points; i++)
1152 {
1153 const size_t idx = i * 2;
1154 points[idx + 0] *= preview_width;
1155 points[idx + 1] *= preview_height;
1156 }
1157}
1158
1159void dt_dev_coordinates_preview_abs_to_image_norm(dt_develop_t *dev, float *points, size_t num_points)
1160{
1161 if(IS_NULL_PTR(dev) || IS_NULL_PTR(points) || num_points == 0) return;
1162 const float preview_width = dev->roi.preview_width;
1163 const float preview_height = dev->roi.preview_height;
1164 if(preview_width == 0.0f || preview_height == 0.0f) return;
1165
1166 const float inv_width = 1.f / preview_width;
1167 const float inv_height = 1.f / preview_height;
1168 for(size_t i = 0; i < num_points; i++)
1169 {
1170 const size_t idx = i * 2;
1171 points[idx + 0] *= inv_width;
1172 points[idx + 1] *= inv_height;
1173 }
1174}
1175
1177{
1178 return (dev->image_storage.id == imgid) ? 1 : 0;
1179}
1180
1186
1188{
1189 if(dev->proxy.masks.module && dev->proxy.masks.list_change)
1190 dev->proxy.masks.list_change(dev->proxy.masks.module);
1191}
1193{
1194 if(dev->proxy.masks.module && dev->proxy.masks.list_update)
1195 dev->proxy.masks.list_update(dev->proxy.masks.module);
1196}
1197void dt_dev_masks_list_remove(dt_develop_t *dev, int formid, int parentid)
1198{
1199 if(dev->proxy.masks.module && dev->proxy.masks.list_remove)
1200 dev->proxy.masks.list_remove(dev->proxy.masks.module, formid, parentid);
1201}
1203 const int selectid, const int throw_event)
1204{
1205 if(dev->proxy.masks.module && dev->proxy.masks.selection_change)
1206 dev->proxy.masks.selection_change(dev->proxy.masks.module, module, selectid, throw_event);
1207}
1208
1209void dt_dev_snapshot_request(dt_develop_t *dev, const char *filename)
1210{
1211 dev->proxy.snapshot.filename = filename;
1212 dev->proxy.snapshot.request = TRUE;
1214}
1215
1218{
1219 // we create the new module
1220 dt_iop_module_t *module = (dt_iop_module_t *)calloc(1, sizeof(dt_iop_module_t));
1221 if(dt_iop_load_module(module, base->so, base->dev)) return NULL;
1222 module->instance = base->instance;
1223
1224 // we set the multi-instance priority and the iop order
1225 int pmax = 0;
1226 for(GList *modules = base->dev->iop; modules; modules = g_list_next(modules))
1227 {
1228 dt_iop_module_t *mod = (dt_iop_module_t *)modules->data;
1229 if(mod->instance == base->instance)
1230 {
1231 if(pmax < mod->multi_priority) pmax = mod->multi_priority;
1232 }
1233 }
1234 // create a unique multi-priority
1235 pmax += 1;
1236 dt_iop_update_multi_priority(module, pmax);
1237
1238 // add this new module position into the iop-order-list
1240
1241 // since we do not rename the module we need to check that an old module does not have the same name. Indeed
1242 // the multi_priority
1243 // are always rebased to start from 0, to it may be the case that the same multi_name be generated when
1244 // duplicating a module.
1245 int pname = module->multi_priority;
1246 char mname[128];
1247
1248 do
1249 {
1250 snprintf(mname, sizeof(mname), "%d", pname);
1251 gboolean dup = FALSE;
1252
1253 for(GList *modules = base->dev->iop; modules; modules = g_list_next(modules))
1254 {
1255 dt_iop_module_t *mod = (dt_iop_module_t *)modules->data;
1256 if(mod->instance == base->instance)
1257 {
1258 if(strcmp(mname, mod->multi_name) == 0)
1259 {
1260 dup = TRUE;
1261 break;
1262 }
1263 }
1264 }
1265
1266 if(dup)
1267 pname++;
1268 else
1269 break;
1270 } while(1);
1271
1272 // the multi instance name
1273 g_strlcpy(module->multi_name, mname, sizeof(module->multi_name));
1274 // we insert this module into dev->iop
1275 base->dev->iop = g_list_insert_sorted(base->dev->iop, module, dt_sort_iop_by_order);
1276
1277 // always place the new instance after the base one
1278 if(!dt_ioppr_move_iop_after(base->dev, module, base))
1279 {
1280 fprintf(stderr, "[dt_dev_module_duplicate] can't move new instance after the base one\n");
1281 }
1282
1283 // that's all. rest of insertion is gui work !
1284 return module;
1285}
1286
1287
1288
1290{
1291 // if(darktable.gui->reset) return;
1292 int del = 0;
1293
1294 if(dev->gui_attached)
1295 {
1298
1299 const int history_end = dt_dev_get_history_end_ext(dev);
1300 int removed_before_end = 0;
1301 int history_pos = 0;
1302 GList *elem = dev->history;
1303 while(!IS_NULL_PTR(elem))
1304 {
1305 GList *next = g_list_next(elem);
1306 dt_dev_history_item_t *hist = (dt_dev_history_item_t *)(elem->data);
1307
1308 if(module == hist->module)
1309 {
1310 dt_print(DT_DEBUG_HISTORY, "[dt_module_remode] removing obsoleted history item: %s %s %p %p\n",
1311 hist->op_name, hist->multi_name, module, hist->module);
1313 dev->history = g_list_delete_link(dev->history, elem);
1314 if(history_pos < history_end) removed_before_end++;
1315 del = 1;
1316 }
1317 history_pos++;
1318 elem = next;
1319 }
1320
1321 if(removed_before_end > 0)
1322 dt_dev_set_history_end_ext(dev, MAX(0, history_end - removed_before_end));
1323
1327 }
1328
1329 // and we remove it from the list
1330 for(GList *modules = dev->iop; modules; modules = g_list_next(modules))
1331 {
1332 dt_iop_module_t *mod = (dt_iop_module_t *)modules->data;
1333 if(mod == module)
1334 {
1335 dev->iop = g_list_delete_link(dev->iop, modules);
1336 break;
1337 }
1338 }
1339}
1340
1348
1351{
1352 const int nb_instances = GPOINTER_TO_INT(
1353 g_hash_table_lookup(state->instance_counts, GINT_TO_POINTER(module->instance)));
1354
1355 dt_iop_module_t *mod_prev = (dt_iop_module_t *)g_hash_table_lookup(state->prev_visible, module);
1356 dt_iop_module_t *mod_next = (dt_iop_module_t *)g_hash_table_lookup(state->next_visible, module);
1357
1358 const gboolean move_next = mod_next
1359 ? dt_ioppr_check_can_move_after_iop(dev->iop, module, mod_next)
1360 : -1.0;
1361 const gboolean move_prev = mod_prev
1362 ? dt_ioppr_check_can_move_before_iop(dev->iop, module, mod_prev)
1363 : -1.0;
1364
1365 module->multi_show_new = !(module->flags() & IOP_FLAGS_ONE_INSTANCE);
1366 // Never allow deleting the base instance (multi_priority == 0) nor modules limited to one instance.
1367 module->multi_show_close =
1368 (nb_instances > 1 && module->multi_priority > 0 && !(module->flags() & IOP_FLAGS_ONE_INSTANCE));
1369 if(!IS_NULL_PTR(mod_next))
1370 module->multi_show_up = move_next;
1371 else
1372 module->multi_show_up = 0;
1373 if(!IS_NULL_PTR(mod_prev))
1374 module->multi_show_down = move_prev;
1375 else
1376 module->multi_show_down = 0;
1377
1378 // If it's an additional instance supposed to be added by an history item after
1379 // the current history_end cursor, conceptually it doesn't exist yet,
1380 // even though it's dangling there on the pipe. So hide it from GUI.
1381 if(nb_instances > 1
1382 && module->multi_priority > 0
1383 && !g_hash_table_contains(state->modules_in_history, module))
1384 gtk_widget_hide(module->expander);
1385}
1386
1387// FIXME: this function should just disappear, as it mixes concepts from multi-instances from before
1388// pipeline reordering and pipeline reordering.
1389// Multi-instances concept should just be ditched entirely.
1391{
1392 dt_ioppr_check_iop_order(dev, 0, "dt_dev_modules_update_multishow");
1393 const int history_end = dt_dev_get_history_end_ext(dev);
1394
1396 state.instance_counts = g_hash_table_new(g_direct_hash, g_direct_equal);
1397 state.modules_in_history = g_hash_table_new(g_direct_hash, g_direct_equal);
1398 state.prev_visible = g_hash_table_new(g_direct_hash, g_direct_equal);
1399 state.next_visible = g_hash_table_new(g_direct_hash, g_direct_equal);
1400
1401 // Precompute how many instances exist for each base module.
1402 for(GList *modules = dev->iop; modules; modules = g_list_next(modules))
1403 {
1404 const dt_iop_module_t *mod = (dt_iop_module_t *)modules->data;
1405 gpointer key = GINT_TO_POINTER(mod->instance);
1406 int count = GPOINTER_TO_INT(g_hash_table_lookup(state.instance_counts, key));
1407 g_hash_table_replace(state.instance_counts, key, GINT_TO_POINTER(count + 1));
1408 }
1409
1410 // Precompute which modules exist in history up to history_end.
1411 int history_pos = 0;
1412 for(GList *history = g_list_first(dev->history);
1413 history && history_pos < history_end;
1414 history = g_list_next(history), history_pos++)
1415 {
1416 dt_dev_history_item_t *hist = (dt_dev_history_item_t *)history->data;
1417 if(hist->module) g_hash_table_add(state.modules_in_history, hist->module);
1418 }
1419
1420 // Precompute previous visible module in pipeline order.
1421 dt_iop_module_t *last_visible = NULL;
1422 for(GList *modules = g_list_first(dev->iop); modules; modules = g_list_next(modules))
1423 {
1424 dt_iop_module_t *mod = (dt_iop_module_t *)modules->data;
1426 {
1427 g_hash_table_insert(state.prev_visible, mod, last_visible);
1428 last_visible = mod;
1429 }
1430 }
1431
1432 // Precompute next visible module in GUI order (reverse pipeline).
1433 last_visible = NULL;
1434 for(GList *modules = g_list_last(dev->iop); modules; modules = g_list_previous(modules))
1435 {
1436 dt_iop_module_t *mod = (dt_iop_module_t *)modules->data;
1438 {
1439 g_hash_table_insert(state.next_visible, mod, last_visible);
1440 last_visible = mod;
1441 }
1442 }
1443
1444 for(GList *modules = dev->iop; modules; modules = g_list_next(modules))
1445 {
1446 dt_iop_module_t *mod = (dt_iop_module_t *)modules->data;
1447
1450 }
1451
1452 g_hash_table_destroy(state.instance_counts);
1453 g_hash_table_destroy(state.modules_in_history);
1454 g_hash_table_destroy(state.prev_visible);
1455 g_hash_table_destroy(state.next_visible);
1456}
1457
1458gchar *dt_history_item_get_label(const struct dt_iop_module_t *module)
1459{
1460 gchar *label;
1461 /* create a history button and add to box */
1462 if(!module->multi_name[0] || strcmp(module->multi_name, "0") == 0)
1463 label = g_strdup(module->name());
1464 else
1465 {
1466 label = g_strdup_printf("%s %s", module->name(), module->multi_name);
1467 }
1468 return label;
1469}
1470
1471gchar *dt_dev_get_multi_name(const struct dt_iop_module_t *module)
1472{
1473 gboolean has_multi_name = g_strcmp0(module->multi_name, "0") != 0 && g_strcmp0(module->multi_name, "") != 0;
1474 gchar *label = has_multi_name ? g_strdup(module->multi_name) : g_strdup("");
1475
1476 return label;
1477}
1478
1480{
1481 gchar *module_multi_name = dt_dev_get_multi_name(module);
1482 gboolean has_multi_name = g_strcmp0(module_multi_name, "") != 0;
1483 // fallback to module name if no multi name
1484 gchar *module_label = has_multi_name ? g_strdup(module_multi_name) : dt_history_item_get_name(module);
1485 gchar *group_name = g_strdup_printf("Mask %s", module_label);
1486 dt_free(module_label);
1487 dt_free(module_multi_name);
1488
1489 return group_name;
1490}
1491
1492
1493gchar *dt_history_item_get_name(const struct dt_iop_module_t *module)
1494{
1495 gchar *label;
1496 /* create a history button and add to box */
1497 if(!module->multi_name[0] || strcmp(module->multi_name, "0") == 0)
1498 label = delete_underscore(module->name());
1499 else
1500 {
1501 gchar *clean_name = delete_underscore(module->name());
1502 label = g_strdup_printf("%s %s", clean_name, module->multi_name);
1503 dt_free(clean_name);
1504 }
1505 dt_capitalize_label(label);
1506 return label;
1507}
1508
1510{
1511 gchar *clean_name = delete_underscore(module->name());
1512 gchar *label;
1513 /* create a history button and add to box */
1514 if(!module->multi_name[0] || strcmp(module->multi_name, "0") == 0)
1515 label = g_markup_escape_text(clean_name, -1);
1516 else
1517 label = g_markup_printf_escaped("%s <span size=\"smaller\">%s</span>", clean_name, module->multi_name);
1518 dt_free(clean_name);
1519 return label;
1520}
1521
1522static int dt_dev_distort_backtransform_locked(const dt_dev_pixelpipe_t *pipe, const double iop_order,
1523 const int transf_direction, float *points, size_t points_count);
1524
1525int dt_dev_coordinates_raw_abs_to_image_abs(dt_develop_t *dev, float *points, size_t points_count)
1526{
1527 return dt_dev_distort_transform_plus(dev->virtual_pipe, 0.0f, DT_DEV_TRANSFORM_DIR_ALL, points, points_count);
1528}
1529
1530int dt_dev_coordinates_image_abs_to_raw_abs(dt_develop_t *dev, float *points, size_t points_count)
1531{
1532 return dt_dev_distort_backtransform_locked(dev->virtual_pipe, 0.0f, DT_DEV_TRANSFORM_DIR_ALL, points, points_count);
1533}
1534
1535// only call directly or indirectly from dt_dev_distort_transform_plus, so that it runs with the history locked
1536int dt_dev_distort_transform_locked(const dt_dev_pixelpipe_t *pipe, const double iop_order,
1537 const int transf_direction, float *points, size_t points_count)
1538{
1539 for(GList *pieces = g_list_first(pipe->nodes); pieces; pieces = g_list_next(pieces))
1540 {
1541 dt_dev_pixelpipe_iop_t *piece = (dt_dev_pixelpipe_iop_t *)(pieces->data);
1542 dt_iop_module_t *module = piece->module;
1543 if(piece->enabled
1544 && ((transf_direction == DT_DEV_TRANSFORM_DIR_ALL)
1545 || (transf_direction == DT_DEV_TRANSFORM_DIR_FORW_INCL && module->iop_order >= iop_order)
1546 || (transf_direction == DT_DEV_TRANSFORM_DIR_FORW_EXCL && module->iop_order > iop_order)
1547 || (transf_direction == DT_DEV_TRANSFORM_DIR_BACK_INCL && module->iop_order <= iop_order)
1548 || (transf_direction == DT_DEV_TRANSFORM_DIR_BACK_EXCL && module->iop_order < iop_order))
1549 && !dt_dev_pixelpipe_activemodule_disables_currentmodule(pipe->dev, module))
1550 {
1551 module->distort_transform(module, pipe, piece, points, points_count);
1552 }
1553 }
1554 return 1;
1555}
1556
1557int dt_dev_distort_transform_plus(const dt_dev_pixelpipe_t *pipe, const double iop_order, const int transf_direction,
1558 float *points, size_t points_count)
1559{
1560 dt_dev_distort_transform_locked(pipe, iop_order, transf_direction, points, points_count);
1561 return 1;
1562}
1563
1564// Internal backtransform loop. Keep this file-local so callers use the public wrappers.
1565static int dt_dev_distort_backtransform_locked(const dt_dev_pixelpipe_t *pipe, const double iop_order,
1566 const int transf_direction, float *points, size_t points_count)
1567{
1568 for(GList *pieces = g_list_last(pipe->nodes); pieces; pieces = g_list_previous(pieces))
1569 {
1570 dt_dev_pixelpipe_iop_t *piece = (dt_dev_pixelpipe_iop_t *)(pieces->data);
1571 dt_iop_module_t *module = piece->module;
1572 if(piece->enabled
1573 && ((transf_direction == DT_DEV_TRANSFORM_DIR_ALL)
1574 || (transf_direction == DT_DEV_TRANSFORM_DIR_FORW_INCL && module->iop_order >= iop_order)
1575 || (transf_direction == DT_DEV_TRANSFORM_DIR_FORW_EXCL && module->iop_order > iop_order)
1576 || (transf_direction == DT_DEV_TRANSFORM_DIR_BACK_INCL && module->iop_order <= iop_order)
1577 || (transf_direction == DT_DEV_TRANSFORM_DIR_BACK_EXCL && module->iop_order < iop_order))
1578 && !dt_dev_pixelpipe_activemodule_disables_currentmodule(pipe->dev, module))
1579 {
1580 module->distort_backtransform(module, pipe, piece, points, points_count);
1581 }
1582 }
1583 return 1;
1584}
1585
1586int dt_dev_distort_backtransform_plus(const dt_dev_pixelpipe_t *pipe, const double iop_order, const int transf_direction,
1587 float *points, size_t points_count)
1588{
1589 const int success = dt_dev_distort_backtransform_locked(pipe, iop_order, transf_direction, points, points_count);
1590 return success;
1591}
1592
1594 struct dt_iop_module_t *module)
1595{
1596 for(const GList *pieces = g_list_last(pipe->nodes); pieces; pieces = g_list_previous(pieces))
1597 {
1598 dt_dev_pixelpipe_iop_t *piece = (dt_dev_pixelpipe_iop_t *)(pieces->data);
1599 if(piece->module == module)
1600 {
1601 return piece;
1602 }
1603 }
1604 return NULL;
1605}
1606
1607// set the module list order
1613
1615{
1617
1618 /* record current history state : before change (needed for undo) */
1619 if(dev->gui_attached && cv->view((dt_view_t *)cv) == DT_VIEW_DARKROOM)
1620 {
1622 }
1623}
1624
1626{
1628
1629 /* record current history state : after change (needed for undo) */
1630 if(dev->gui_attached && cv->view((dt_view_t *)cv) == DT_VIEW_DARKROOM)
1631 {
1634 }
1635}
1636
1638{
1639 if(dev->gui_attached)
1640 {
1642 const gboolean state = dev->mask_lock;
1644 return state;
1645 }
1646 return FALSE;
1647}
1648
1649void dt_masks_set_lock_mode(dt_develop_t *dev, gboolean mode)
1650{
1651 if(dev->gui_attached)
1652 {
1654 dev->mask_lock = mode;
1656 }
1657}
1658
1660{
1661 const int num_items = g_list_length(dev->history);
1662 return CLAMP(dev->history_end, 0, num_items);
1663}
1664
1665void dt_dev_set_history_end_ext(dt_develop_t *dev, const uint32_t index)
1666{
1667 const int num_items = g_list_length(dev->history);
1668 dev->history_end = CLAMP(index, 0, num_items);
1670}
1671
1672void dt_dev_append_changed_tag(const int32_t imgid)
1673{
1674 /* attach changed tag reflecting actual change */
1675 guint tagid = 0;
1676 dt_tag_new("darktable|changed", &tagid);
1677 const gboolean tag_change = dt_tag_attach(tagid, imgid, FALSE, FALSE);
1679}
1680
1682{
1683 uint64_t hash = 5381;
1684 for(GList *form = g_list_first(dev->forms); form; form = g_list_next(form))
1685 {
1686 dt_masks_form_t *shape = (dt_masks_form_t *)form->data;
1687 hash = dt_masks_group_get_hash(hash, shape);
1688 }
1689
1690 // Keep on accumulating "changed" states until something saves the new stack
1691 // and resets that to 0
1692 uint64_t old_hash = dev->forms_hash;
1693 dev->forms_changed |= (old_hash != hash);
1694 dev->forms_hash = hash;
1695}
1696
1698{
1699 if(!dev->roi.gui_inited || !dev->roi.raw_inited) return -1.f;
1700
1701 return fminf(fminf((float)dev->roi.width / (float)dev->roi.processed_width,
1702 (float)dev->roi.height / (float)dev->roi.processed_height),
1703 1.f);
1704}
1705
1707{
1708 if(IS_NULL_PTR(dev)) return 1.0f;
1709 return dev->roi.scaling / darktable.gui->ppd;
1710}
1711
1713{
1714 return dt_dev_get_fit_scale(dev);
1715}
1716
1718{
1719 if(IS_NULL_PTR(dev)) return 1.0f;
1720 return scaling * dev->roi.natural_scale / darktable.gui->ppd;
1721}
1722
1724{
1725 if(IS_NULL_PTR(dev) || IS_NULL_PTR(point)) return;
1726 point[0] = 0.5f * dev->roi.orig_width;
1727 point[1] = 0.5f * dev->roi.orig_height;
1728}
1729
1730void dt_dev_get_image_box_in_widget(const dt_develop_t *dev, const int32_t width, const int32_t height, float *box)
1731{
1732 if(IS_NULL_PTR(dev) || IS_NULL_PTR(box)) return;
1733
1734 const float scale = dev->roi.scaling / darktable.gui->ppd;
1735 const float roi_width = fminf(width, dev->roi.preview_width * scale);
1736 const float roi_height = fminf(height, dev->roi.preview_height * scale);
1737 const float border = dev->roi.border_size;
1738
1739 box[0] = fmaxf(border, 0.5f * (width - roi_width));
1740 box[1] = fmaxf(border, 0.5f * (height - roi_height));
1741 box[2] = fminf(width - 2 * border, roi_width);
1742 box[3] = fminf(height - 2 * border, roi_height);
1743}
1744
1746{
1747 if(IS_NULL_PTR(dev)) return 1.f;
1748 return dev->roi.scaling * dev->roi.natural_scale;
1749}
1750
1752{
1753 dev->roi.natural_scale = -1.f;
1754 dev->roi.scaling = 1.f;
1755 dev->roi.x = 0.5f;
1756 dev->roi.y = 0.5f;
1757}
1758
1759void dt_dev_convert_roi(const dt_develop_t *dev, const dt_iop_roi_t *roi_in, dt_iop_roi_t *roi_out,
1760 const dt_dev_roi_space_t from, const dt_dev_roi_space_t to)
1761{
1762 if(IS_NULL_PTR(dev) || IS_NULL_PTR(roi_in) || IS_NULL_PTR(roi_out)) return;
1763
1764 *roi_out = *roi_in;
1765 if(from == to) return;
1766
1767 const float factor = (from == DT_DEV_ROI_GUI_LOGICAL && to == DT_DEV_ROI_PIPELINE)
1768 ? darktable.gui->ppd
1769 : 1.0f / darktable.gui->ppd;
1770
1771 // x/y/width/height belong to the GUI/pipeline geometry boundary and therefore
1772 // follow the ppd factor. roi->scale stays unchanged because it expresses the
1773 // image-space sampling ratio, which must not depend on GUI density.
1774 roi_out->x = lroundf(roi_in->x * factor);
1775 roi_out->y = lroundf(roi_in->y * factor);
1776 roi_out->width = lroundf(roi_in->width * factor);
1777 roi_out->height = lroundf(roi_in->height * factor);
1778 roi_out->scale = roi_in->scale * factor;
1779}
1780
1781gboolean dt_dev_clip_roi(dt_develop_t *dev, cairo_t *cr, int32_t width, int32_t height)
1782{
1783 // DO NOT MODIFIY !! //
1784
1785 const float wd = dev->roi.preview_width;
1786 const float ht = dev->roi.preview_height;
1787 if(wd == 0.f || ht == 0.f) return TRUE;
1788
1789 const float zoom_scale = dt_dev_get_overlay_scale(dev);
1790 const int32_t border = dev->roi.border_size;
1791 const float roi_width = fminf(width, wd * zoom_scale);
1792 const float roi_height = fminf(height, ht * zoom_scale);
1793
1794 const float rec_x = fmaxf(border, (width - roi_width) * 0.5f);
1795 const float rec_y = fmaxf(border, (height - roi_height) * 0.5f);
1796 const float rec_w = fminf(width - 2 * border, roi_width);
1797 const float rec_h = fminf(height - 2 * border, roi_height);
1798
1799 cairo_rectangle(cr, rec_x, rec_y, rec_w, rec_h);
1800 cairo_clip(cr);
1801
1802 return FALSE;
1803}
1804
1805static gboolean _dev_translate_roi(dt_develop_t *dev, cairo_t *cr, int32_t width, int32_t height)
1806{
1807 // DO NOT MODIFIY !! //
1808 // used by preview image scalling, guide and modules //
1809 int proc_wd = 0;
1810 int proc_ht = 0;
1811 dt_dev_get_processed_size(dev, &proc_wd, &proc_ht);
1812 if(proc_wd == 0.f || proc_ht == 0.f) return TRUE;
1813
1814 // Get image's origin position and scale
1815 const float zoom_scale = dt_dev_get_zoom_level(dev) / darktable.gui->ppd;
1816 const float tx = 0.5f * width - dev->roi.x * proc_wd * zoom_scale;
1817 const float ty = 0.5f * height - dev->roi.y * proc_ht * zoom_scale;
1818
1819 cairo_translate(cr, tx, ty);
1820
1821 return FALSE;
1822}
1823
1824gboolean dt_dev_rescale_roi(dt_develop_t *dev, cairo_t *cr, int32_t width, int32_t height)
1825{
1826 if(_dev_translate_roi(dev, cr, width, height))
1827 return TRUE;
1828 const float scale = dt_dev_get_fit_scale(dev);
1829 cairo_scale(cr, scale, scale);
1830
1831 return FALSE;
1832}
1833
1834gboolean dt_dev_rescale_roi_to_input(dt_develop_t *dev, cairo_t *cr, int32_t width, int32_t height)
1835{
1836 if(_dev_translate_roi(dev, cr, width, height))
1837 return TRUE;
1838 const float scale = dt_dev_get_zoom_level(dev) / darktable.gui->ppd;
1839 cairo_scale(cr, scale, scale);
1840
1841 return FALSE;
1842}
1843
1845{
1846 const float natural_scale = dev->roi.natural_scale;
1847
1848 // Limit zoom in to 16x the size of an apparent pixel on screen
1849 const float pixel_actual_size = natural_scale * dev->roi.scaling;
1850 const float pixel_max_size = 16.f;
1851
1852 if(pixel_actual_size >= pixel_max_size)
1853 {
1854 // Restore old scaling (caller should handle this)
1855 dev->roi.scaling = pixel_max_size / natural_scale;
1856 return TRUE;
1857 }
1858
1859 // Limit zoom out to 1/3rd of the fit-to-window size
1860 const float min_scaling = 0.33f;
1861 if(dev->roi.scaling < min_scaling)
1862 {
1863 dev->roi.scaling = min_scaling;
1864 return TRUE;
1865 }
1866 return FALSE;
1867}
1868
1870{
1871 float zoom_level = dt_dev_get_zoom_level(dev);
1872 if(zoom_level <= 0.f) zoom_level = 1.0f;
1873
1874 // Keep mouse hit-tests usable across zoom levels by bounding the selection
1875 // radius once it is expressed in image-space pixels.
1877 DT_PIXEL_APPLY_DPI(4.0f) / zoom_level,
1878 DT_PIXEL_APPLY_DPI(15.0f) / zoom_level);
1879
1881 "[mouse] effect_radius=%0.3f effect_radius_clamped=%0.3f zoom_level=%0.4f ppd=%0.4f\n",
1883 zoom_level, darktable.gui->ppd);
1884}
1885
1886void dt_dev_set_backbuf(dt_backbuf_t *backbuf, const int width, const int height, const size_t bpp,
1887 const int64_t hash, const int64_t history_hash)
1888{
1889 backbuf->height = height;
1890 backbuf->width = width;
1891 dt_dev_backbuf_set_hash(backbuf, hash);
1892 backbuf->bpp = bpp;
1893 dt_dev_backbuf_set_history_hash(backbuf, history_hash);
1894}
1895
1896// clang-format off
1897// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
1898// vim: shiftwidth=2 expandtab tabstop=2 cindent
1899// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
1900// clang-format on
#define TRUE
Definition ashift_lsd.c:162
#define FALSE
Definition ashift_lsd.c:158
void dt_atomic_set_int(dt_atomic_int *var, int value)
int dt_atomic_get_int(dt_atomic_int *var)
int width
Definition bilateral.h:1
int height
Definition bilateral.h:1
static const float scaling
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
void dt_image_init(dt_image_t *img)
char * key
int dt_conf_get_bool(const char *name)
void dt_conf_set_float(const char *name, float val)
float dt_conf_get_float(const char *name)
void dt_conf_set_int(const char *name, int val)
int dt_conf_get_int(const char *name)
void dt_control_queue_redraw_center()
request redraw of center window. This redraws the center view within a gdk critical section to preven...
Definition control.c:861
void dt_control_toast_busy_enter()
Definition control.c:832
void dt_control_log_busy_leave()
Definition control.c:840
int dt_control_running()
Definition control.c:423
void dt_control_log_busy_enter()
Definition control.c:824
void dt_control_toast_busy_leave()
Definition control.c:848
void dt_control_queue_redraw()
request redraw of the workspace. This redraws the whole workspace within a gdk critical section to pr...
Definition control.c:856
void dt_show_times(const dt_times_t *start, const char *prefix)
Definition darktable.c:1580
darktable_t darktable
Definition darktable.c:181
void dt_show_times_f(const dt_times_t *start, const char *prefix, const char *suffix,...)
Definition darktable.c:1594
void dt_print(dt_debug_thread_t thread, const char *msg,...)
Definition darktable.c:1542
#define dt_free_align(ptr)
Definition darktable.h:481
@ DT_DEBUG_PIPE
Definition darktable.h:741
@ DT_DEBUG_HISTORY
Definition darktable.h:740
@ DT_DEBUG_DEV
Definition darktable.h:717
@ DT_DEBUG_MASKS
Definition darktable.h:727
static void dt_free_gpointer(gpointer ptr)
Definition darktable.h:463
#define dt_free(ptr)
Definition darktable.h:456
static void dt_get_times(dt_times_t *t)
Definition darktable.h:921
static gchar * delete_underscore(const char *s)
Definition darktable.h:1083
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
Definition darktable.h:281
void dt_dev_free_history_item(gpointer data)
Free a single history item (used as GList free callback).
void dt_dev_history_undo_invalidate_module(dt_iop_module_t *module)
Invalidate a module pointer inside undo snapshots.
uint64_t dt_dev_history_compute_hash(dt_develop_t *dev)
Get the integrity checksum of the whole history stack. This should be done ONLY when history is chang...
void dt_dev_history_undo_start_record_locked(dt_develop_t *dev)
Start an undo record with history_mutex already locked.
void dt_dev_history_undo_end_record(dt_develop_t *dev)
Finish an undo record for history changes.
void dt_dev_history_undo_end_record_locked(dt_develop_t *dev)
Finish an undo record with history_mutex already locked.
void dt_dev_history_undo_start_record(dt_develop_t *dev)
Start an undo record for history changes.
void dt_dev_write_history_ext(dt_develop_t *dev, const int32_t imgid)
Write dev->history to DB and XMP for a given image id.
void dt_dev_history_notify_change(dt_develop_t *dev, const int32_t imgid)
Notify the rest of the app that history changes were written.
gboolean dt_dev_read_history_ext(dt_develop_t *dev, const int32_t imgid)
Read history and masks from DB and populate dev->history.
void dt_pixelpipe_get_global_hash(dt_dev_pixelpipe_t *pipe)
gboolean dt_dev_pixelpipe_is_backbufer_valid(dt_dev_pixelpipe_t *pipe)
void dt_dev_pixelpipe_get_roi_out(dt_dev_pixelpipe_t *pipe, const int width_in, const int height_in, int *width, int *height)
void dt_dev_pixelpipe_change(dt_dev_pixelpipe_t *pipe)
void dt_dev_pixelpipe_get_roi_in(dt_dev_pixelpipe_t *pipe, const struct dt_iop_roi_t roi_out)
#define dt_dev_pixelpipe_update_zoom_preview(dev)
#define dt_dev_pixelpipe_update_zoom_main(dev)
void dt_dev_signal_modules_moved(dt_develop_t *dev)
Definition develop.c:1608
dt_job_t * dt_dev_process_job_create(dt_develop_t *dev)
Definition develop.c:803
void dt_dev_masks_list_change(dt_develop_t *dev)
Definition develop.c:1187
static gboolean _dev_translate_roi(dt_develop_t *dev, cairo_t *cr, int32_t width, int32_t height)
Definition develop.c:1805
void dt_dev_coordinates_image_abs_to_image_norm(dt_develop_t *dev, float *points, size_t num_points)
Definition develop.c:1075
float dt_dev_get_natural_scale(dt_develop_t *dev)
Definition develop.c:1697
int dt_dev_distort_transform_locked(const dt_dev_pixelpipe_t *pipe, const double iop_order, const int transf_direction, float *points, size_t points_count)
Definition develop.c:1536
void dt_dev_get_processed_size(const dt_develop_t *dev, int *procw, int *proch)
Definition develop.c:979
dt_dev_pixelpipe_iop_t * dt_dev_distort_get_iop_pipe(struct dt_dev_pixelpipe_t *pipe, struct dt_iop_module_t *module)
Definition develop.c:1593
void dt_masks_set_lock_mode(dt_develop_t *dev, gboolean mode)
Definition develop.c:1649
void dt_dev_modulegroups_switch_tab(dt_develop_t *dev, dt_iop_module_t *module)
Definition develop.c:1181
void dt_dev_coordinates_preview_abs_to_image_norm(dt_develop_t *dev, float *points, size_t num_points)
Definition develop.c:1159
int dt_dev_get_thumbnail_size(dt_develop_t *dev)
Definition develop.c:309
void _dev_module_update_multishow(dt_develop_t *dev, struct dt_iop_module_t *module, const dt_dev_multishow_state_t *state)
Definition develop.c:1349
void dt_dev_get_image_box_in_widget(const dt_develop_t *dev, const int32_t width, const int32_t height, float *box)
Get the displayed image rectangle in darkroom widget coordinates.
Definition develop.c:1730
int dt_dev_coordinates_raw_abs_to_image_abs(dt_develop_t *dev, float *points, size_t points_count)
Definition develop.c:1525
void dt_dev_coordinates_raw_norm_to_raw_abs(dt_develop_t *dev, float *points, size_t num_points)
Definition develop.c:1109
void dt_dev_get_widget_center(const dt_develop_t *dev, float *point)
Get the center of the darkroom widget in logical coordinates.
Definition develop.c:1723
void dt_dev_module_remove(dt_develop_t *dev, dt_iop_module_t *module)
Definition develop.c:1289
void dt_dev_cleanup(dt_develop_t *dev)
Definition develop.c:188
static void dt_dev_resync_mipmap_cache(dt_develop_t *dev, dt_dev_pixelpipe_t *pipe, dt_iop_roi_t roi)
Definition develop.c:474
int dt_dev_distort_transform_plus(const dt_dev_pixelpipe_t *pipe, const double iop_order, const int transf_direction, float *points, size_t points_count)
Definition develop.c:1557
float dt_dev_get_overlay_scale(dt_develop_t *dev)
Get the overlay scale factor in GUI logical coordinates.
Definition develop.c:1712
void dt_dev_append_changed_tag(const int32_t imgid)
Definition develop.c:1672
dt_dev_image_storage_t dt_dev_load_image(dt_develop_t *dev, const int32_t imgid)
Definition develop.c:887
void dt_dev_coordinates_image_norm_to_preview_abs(dt_develop_t *dev, float *points, size_t num_points)
Definition develop.c:1144
float dt_dev_get_zoom_level(const dt_develop_t *dev)
Definition develop.c:1745
void dt_dev_coordinates_image_norm_to_widget(dt_develop_t *dev, float *points, size_t num_points)
Definition develop.c:1031
void dt_dev_masks_selection_change(dt_develop_t *dev, struct dt_iop_module_t *module, const int selectid, const int throw_event)
Definition develop.c:1202
void dt_dev_init(dt_develop_t *dev, int32_t gui_attached)
Definition develop.c:128
int dt_dev_is_current_image(dt_develop_t *dev, int32_t imgid)
Definition develop.c:1176
void dt_dev_undo_start_record(dt_develop_t *dev)
Definition develop.c:1614
void dt_dev_snapshot_request(dt_develop_t *dev, const char *filename)
Definition develop.c:1209
gboolean dt_masks_get_lock_mode(dt_develop_t *dev)
Definition develop.c:1637
void dt_dev_darkroom_pipeline(dt_develop_t *dev)
Run darkroom preview and main pipelines from one background loop.
Definition develop.c:557
gchar * dt_history_item_get_label(const struct dt_iop_module_t *module)
Definition develop.c:1458
void dt_dev_coordinates_raw_norm_to_image_norm(dt_develop_t *dev, float *points, size_t num_points)
Definition develop.c:1131
gchar * dt_history_item_get_name_html(const struct dt_iop_module_t *module)
Definition develop.c:1509
void dt_dev_check_zoom_pos_bounds(dt_develop_t *dev, float *dev_x, float *dev_y, float *box_w, float *box_h)
Ensure that the current ROI position is within allowed bounds .
Definition develop.c:944
gboolean dt_dev_check_zoom_scale_bounds(dt_develop_t *dev)
Ensure that the current zoom level is within allowed bounds (for scrolling).
Definition develop.c:1844
void dt_dev_reset_roi(dt_develop_t *dev)
Definition develop.c:1751
dt_iop_module_t * dt_dev_module_duplicate(dt_develop_t *dev, dt_iop_module_t *base)
Definition develop.c:1217
gboolean _resync_pipe_with_history(dt_develop_t *dev, dt_dev_pixelpipe_t *pipe, dt_iop_roi_t *roi, gboolean *needs_update)
Definition develop.c:496
GList * dt_dev_load_modules(dt_develop_t *dev)
Definition develop.c:98
void dt_dev_set_backbuf(dt_backbuf_t *backbuf, const int width, const int height, const size_t bpp, const int64_t hash, const int64_t history_hash)
Definition develop.c:1886
void dt_dev_set_history_end_ext(dt_develop_t *dev, const uint32_t index)
Set the history end index (GUI perspective).
Definition develop.c:1665
gboolean dt_dev_rescale_roi_to_input(dt_develop_t *dev, cairo_t *cr, int32_t width, int32_t height)
Scale the ROI to fit the input size within given width/height, centered.
Definition develop.c:1834
static gboolean _darkroom_pipeline_inputs_ready(const dt_develop_t *dev)
Definition develop.c:294
float dt_dev_get_widget_zoom_scale(const dt_develop_t *dev, const float scaling)
Convert a darkroom scaling factor to GUI logical zoom.
Definition develop.c:1717
float dt_dev_get_zoom_scale(const dt_develop_t *dev, const gboolean preview)
Definition develop.c:880
void dt_dev_coordinates_image_norm_to_raw_norm(dt_develop_t *dev, float *points, size_t num_points)
Definition develop.c:1124
static int dt_dev_distort_backtransform_locked(const dt_dev_pixelpipe_t *pipe, const double iop_order, const int transf_direction, float *points, size_t points_count)
Definition develop.c:1565
gboolean dt_dev_pipelines_share_preview_output(dt_develop_t *dev)
Tell whether the darkroom main and preview pipes currently target the same GUI output.
Definition develop.c:457
void dt_dev_configure_real(dt_develop_t *dev, int wd, int ht)
Definition develop.c:922
void dt_dev_masks_update_hash(dt_develop_t *dev)
Definition develop.c:1681
gboolean dt_dev_clip_roi(dt_develop_t *dev, cairo_t *cr, int32_t width, int32_t height)
Clip the view to the ROI. WARNING: this must be done before any translation.
Definition develop.c:1781
int dt_dev_coordinates_image_abs_to_raw_abs(dt_develop_t *dev, float *points, size_t points_count)
Definition develop.c:1530
void dt_dev_undo_end_record(dt_develop_t *dev)
Definition develop.c:1625
gboolean dt_dev_rescale_roi(dt_develop_t *dev, cairo_t *cr, int32_t width, int32_t height)
Scale the ROI to fit within given width/height, centered.
Definition develop.c:1824
void dt_dev_coordinates_widget_delta_to_image_delta(dt_develop_t *dev, float *points, size_t num_points)
Convert a widget-space distance to processed-image pixels.
Definition develop.c:986
void dt_dev_convert_roi(const dt_develop_t *dev, const dt_iop_roi_t *roi_in, dt_iop_roi_t *roi_out, const dt_dev_roi_space_t from, const dt_dev_roi_space_t to)
Convert a full ROI object between pipeline raster coordinates and GUI logical coordinates.
Definition develop.c:1759
float dt_dev_get_fit_scale(dt_develop_t *dev)
Get the scale factor that maps preview-buffer pixels to GUI coordinates.
Definition develop.c:1706
dt_dev_image_storage_t dt_dev_ensure_image_storage(dt_develop_t *dev, const int32_t imgid)
Definition develop.c:847
int32_t dt_dev_get_history_end_ext(dt_develop_t *dev)
Get the current history end index (GUI perspective).
Definition develop.c:1659
void dt_dev_modules_update_multishow(dt_develop_t *dev)
Definition develop.c:1390
void dt_dev_coordinates_image_norm_to_image_abs(dt_develop_t *dev, float *points, size_t num_points)
Definition develop.c:1060
static gboolean _update_darkroom_roi(dt_develop_t *dev, dt_dev_pixelpipe_t *pipe, int *x, int *y, int *wd, int *ht, float *scale)
Definition develop.c:416
gchar * dt_dev_get_masks_group_name(const struct dt_iop_module_t *module)
Definition develop.c:1479
gboolean dt_dev_pixelpipe_has_preview_output(const dt_develop_t *dev, const dt_dev_pixelpipe_t *pipe, const dt_iop_roi_t *roi)
Definition develop.c:367
void dt_dev_coordinates_widget_to_image_norm(dt_develop_t *dev, float *points, size_t num_points)
Coordinate conversion helpers between widget, normalized image, and absolute image spaces.
Definition develop.c:1003
void dt_dev_update_mouse_effect_radius(dt_develop_t *dev)
Convert absolute output-image coordinates to input image space by calling dt_dev_coordinates_image_ab...
Definition develop.c:1869
static gboolean _dt_dev_refresh_image_storage(dt_develop_t *dev, const int32_t imgid)
Definition develop.c:837
void dt_dev_masks_list_update(dt_develop_t *dev)
Definition develop.c:1192
static gboolean _dt_dev_mipmap_prefetch_full(dt_develop_t *dev, const int32_t imgid)
Definition develop.c:818
static dt_dev_image_storage_t _dt_dev_load_raw(dt_develop_t *dev, const int32_t imgid)
Definition develop.c:862
int dt_dev_distort_backtransform_plus(const dt_dev_pixelpipe_t *pipe, const double iop_order, const int transf_direction, float *points, size_t points_count)
Definition develop.c:1586
gchar * dt_dev_get_multi_name(const struct dt_iop_module_t *module)
Definition develop.c:1471
void dt_dev_masks_list_remove(dt_develop_t *dev, int formid, int parentid)
Definition develop.c:1197
static int32_t dt_dev_process_job_run(dt_job_t *job)
Definition develop.c:796
void dt_dev_coordinates_raw_abs_to_raw_norm(dt_develop_t *dev, float *points, size_t num_points)
Definition develop.c:1092
void dt_dev_coordinates_image_abs_to_raw_norm(dt_develop_t *dev, float *points, size_t num_points)
Definition develop.c:1138
gchar * dt_history_item_get_name(const struct dt_iop_module_t *module)
Definition develop.c:1493
void dt_dev_start_all_pipelines(dt_develop_t *dev)
Definition develop.c:811
static uint64_t dt_dev_get_history_hash(const dt_develop_t *dev)
Definition develop.h:504
@ DT_DEV_PIXELPIPE_DISPLAY_NONE
Definition develop.h:117
@ DT_DEV_TRANSFORM_DIR_FORW_INCL
Definition develop.h:103
@ DT_DEV_TRANSFORM_DIR_ALL
Definition develop.h:102
dt_dev_roi_space_t
Definition develop.h:110
@ DT_DEV_ROI_GUI_LOGICAL
Definition develop.h:112
@ DT_DEV_ROI_PIPELINE
Definition develop.h:111
static void dt_dev_set_history_hash(dt_develop_t *dev, const uint64_t history_hash)
Definition develop.h:509
dt_dev_image_storage_t
Definition develop.h:523
@ DT_DEV_IMAGE_STORAGE_DB_NOT_READ
Definition develop.h:526
@ DT_DEV_IMAGE_STORAGE_OK
Definition develop.h:524
@ DT_DEV_IMAGE_STORAGE_MIPMAP_NOT_FOUND
Definition develop.h:525
#define dt_pthread_rwlock_destroy
Definition dtpthread.h:391
static int dt_pthread_mutex_unlock(dt_pthread_mutex_t *mutex) RELEASE(mutex) NO_THREAD_SAFETY_ANALYSIS
Definition dtpthread.h:374
static int dt_pthread_mutex_init(dt_pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr)
Definition dtpthread.h:359
#define dt_pthread_rwlock_wrlock
Definition dtpthread.h:394
static int dt_pthread_mutex_destroy(dt_pthread_mutex_t *mutex)
Definition dtpthread.h:379
#define dt_pthread_rwlock_init
Definition dtpthread.h:390
#define dt_pthread_rwlock_unlock
Definition dtpthread.h:392
static int dt_pthread_mutex_lock(dt_pthread_mutex_t *mutex) ACQUIRE(mutex) NO_THREAD_SAFETY_ANALYSIS
Definition dtpthread.h:364
void dt_iop_buffer_dsc_update_bpp(dt_iop_buffer_dsc_t *dsc)
Definition format.c:28
void dt_capitalize_label(gchar *text)
Definition gtk.c:3150
#define DT_PIXEL_APPLY_DPI(value)
Definition gtk.h:90
void dt_gui_throttle_cancel(gpointer source)
void dt_gui_throttle_record_runtime(const dt_dev_pixelpipe_t *pipe, const gint64 runtime_us)
void dt_image_cache_read_release(dt_image_cache_t *cache, const dt_image_t *img)
dt_image_t * dt_image_cache_get(dt_image_cache_t *cache, const int32_t imgid, char mode)
void dt_image_cache_write_release(dt_image_cache_t *cache, dt_image_t *img, dt_image_cache_write_mode_t mode)
@ DT_IMAGE_CACHE_SAFE
Definition image_cache.h:49
int bpp
void dt_iop_cleanup_module(dt_iop_module_t *module)
Definition imageop.c:1561
int dt_iop_load_module(dt_iop_module_t *module, dt_iop_module_so_t *module_so, dt_develop_t *dev)
Definition imageop.c:1550
int dt_iop_load_module_by_so(dt_iop_module_t *module, dt_iop_module_so_t *so, dt_develop_t *dev)
Definition imageop.c:466
void dt_iop_nap(int32_t usec)
Definition imageop.c:2899
gboolean dt_iop_gui_module_is_visible(dt_iop_module_t *module)
Definition imageop.c:734
void dt_iop_update_multi_priority(dt_iop_module_t *module, int new_priority)
Definition imageop.c:3043
gint dt_sort_iop_by_order(gconstpointer a, gconstpointer b)
Compare two module instances by iop_order for sorting.
Definition iop_order.c:2002
gboolean dt_ioppr_check_can_move_before_iop(GList *iop_list, dt_iop_module_t *module, dt_iop_module_t *module_next)
Validate whether module can be moved before module_next.
Definition iop_order.c:2015
gboolean dt_ioppr_check_can_move_after_iop(GList *iop_list, dt_iop_module_t *module, dt_iop_module_t *module_prev)
Validate whether module can be moved after module_prev.
Definition iop_order.c:2184
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:2251
void dt_ioppr_insert_module_instance(struct dt_develop_t *dev, dt_iop_module_t *module)
Ensure a module instance has an entry in dev->iop_order_list.
Definition iop_order.c:2349
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:2377
void dt_ioppr_cleanup_profile_info(dt_iop_order_iccprofile_info_t *profile_info)
static const float x
dt_job_t * dt_control_job_create(dt_job_execute_callback execute, const char *msg,...)
Definition jobs.c:135
int32_t dt_control_add_job_res(dt_control_t *control, _dt_job_t *job, int32_t res)
Definition jobs.c:349
void * dt_control_job_get_params(const _dt_job_t *job)
Definition jobs.c:129
void dt_control_job_set_params(_dt_job_t *job, void *params, dt_job_destroy_callback callback)
Definition jobs.c:112
#define DT_CTL_WORKER_DARKROOM
Definition jobs.h:38
void dt_masks_free_form(dt_masks_form_t *form)
uint64_t dt_masks_group_get_hash(uint64_t hash, dt_masks_form_t *form)
#define CLAMPF(a, mn, mx)
Definition math.h:89
void dt_mipmap_cache_swap_at_size(dt_mipmap_cache_t *cache, const int32_t imgid, const dt_mipmap_size_t mip, const uint8_t *const in, const int32_t width, const int32_t height, dt_colorspaces_color_profile_type_t profile)
dt_mipmap_size_t dt_mipmap_cache_get_fitting_size(const dt_mipmap_cache_t *cache, const int32_t width, const int32_t height, const uint32_t imgid)
#define dt_mipmap_cache_get(A, B, C, D, E, F)
@ DT_MIPMAP_BLOCKING
#define dt_mipmap_cache_release(A, B)
dt_mipmap_size_t
@ DT_MIPMAP_FULL
const float factor
Definition pdf.h:90
@ DT_DEV_PIXELPIPE_PREVIEW
Definition pixelpipe.h:40
@ DT_DEV_PIXELPIPE_FULL
Definition pixelpipe.h:39
gboolean dt_dev_pixelpipe_cache_peek(dt_dev_pixelpipe_cache_t *cache, const uint64_t hash, void **data, dt_pixel_cache_entry_t **entry, const int preferred_devid, void **cl_mem_output)
Non-owning lookup of an existing cache line.
void dt_dev_pixelpipe_cache_rdlock_entry(dt_dev_pixelpipe_cache_t *cache, gboolean lock, dt_pixel_cache_entry_t *cache_entry)
Lock or release the read lock on the entry.
Pixelpipe cache for storing intermediate results in the pixelpipe.
#define DT_PIXELPIPE_CACHE_HASH_INVALID
void dt_dev_pixelpipe_set_input(dt_dev_pixelpipe_t *pipe, int32_t imgid, int width, int height, float iscale, dt_mipmap_size_t size)
void dt_dev_pixelpipe_reset_reentry(dt_dev_pixelpipe_t *pipe)
gboolean dt_dev_pixelpipe_has_reentry(dt_dev_pixelpipe_t *pipe)
int dt_dev_pixelpipe_init(dt_dev_pixelpipe_t *pipe, dt_develop_t *dev)
gboolean dt_dev_pixelpipe_get_realtime(const dt_dev_pixelpipe_t *pipe)
char * dt_pixelpipe_get_pipe_name(dt_dev_pixelpipe_type_t pipe_type)
int dt_dev_pixelpipe_init_preview(dt_dev_pixelpipe_t *pipe, dt_develop_t *dev)
void dt_dev_pixelpipe_cleanup(dt_dev_pixelpipe_t *pipe)
int dt_dev_pixelpipe_process(dt_dev_pixelpipe_t *pipe, dt_iop_roi_t roi)
static dt_dev_pixelpipe_cache_request_t dt_dev_pixelpipe_get_cache_request(const dt_dev_pixelpipe_t *pipe)
static dt_dev_pixelpipe_change_t dt_dev_pixelpipe_get_changed(const dt_dev_pixelpipe_t *pipe)
static uint64_t dt_dev_pixelpipe_get_hash(const dt_dev_pixelpipe_t *pipe)
static void dt_dev_pixelpipe_or_changed(dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_change_t flags)
static void dt_dev_pixelpipe_set_cache_request(dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_cache_request_t request, const struct dt_iop_module_t *module)
@ DT_DEV_PIPE_REENTRY
@ DT_DEV_PIPE_CACHE_REQUEST
@ DT_DEV_PIPE_SYNCH
@ DT_DEV_PIPE_TOP_CHANGED
@ DT_DEV_PIPE_REMOVE
@ DT_DEV_PIPE_UNCHANGED
static uint64_t dt_dev_pixelpipe_get_history_hash(const dt_dev_pixelpipe_t *pipe)
static void dt_dev_pixelpipe_set_history_hash(dt_dev_pixelpipe_t *pipe, const uint64_t history_hash)
static void dt_dev_backbuf_set_hash(dt_backbuf_t *backbuf, const uint64_t hash)
static void dt_dev_backbuf_set_history_hash(dt_backbuf_t *backbuf, const uint64_t history_hash)
dt_dev_pixelpipe_cache_request_t
@ DT_DEV_PIXELPIPE_CACHE_REQUEST_BACKBUF
@ DT_DEV_PIXELPIPE_CACHE_REQUEST_NONE
@ DT_DEV_PIXELPIPE_CACHE_REQUEST_MODULE
#define DT_DEBUG_CONTROL_SIGNAL_RAISE(ctlsig, signal,...)
Definition signal.h:347
@ DT_SIGNAL_DEVELOP_HISTORY_CHANGE
This signal is raised when develop history is changed no param, no returned value.
Definition signal.h:204
@ DT_SIGNAL_DEVELOP_PREVIEW_PIPE_FINISHED
This signal is raised when develop preview pipe process is finished no param, no returned value.
Definition signal.h:174
@ DT_SIGNAL_HISTORY_RESYNC
This signal is raised once darkroom history has been resynchronized into all live pipelines....
Definition signal.h:209
@ DT_SIGNAL_DEVELOP_UI_PIPE_FINISHED
This signal is raised when pipe is finished and the gui is attached no param, no returned value.
Definition signal.h:179
@ DT_SIGNAL_DEVELOP_MODULE_MOVED
This signal is raised when order of modules in pipeline is changed.
Definition signal.h:218
@ DT_SIGNAL_DEVELOP_MODULEGROUPS_SET
This signal is raised to request a modulegroups update. 1 : dt_iop_module_t *module,...
Definition signal.h:191
@ DT_SIGNAL_TAG_CHANGED
This signal is raised when a tag is added/deleted/changed
Definition signal.h:130
const float uint32_t state[4]
unsigned __int64 uint64_t
Definition strptime.c:75
struct dt_dev_pixelpipe_cache_t * pixelpipe_cache
Definition darktable.h:790
struct dt_gui_gtk_t * gui
Definition darktable.h:775
struct dt_colorspaces_t * color_profiles
Definition darktable.h:788
struct dt_mipmap_cache_t * mipmap_cache
Definition darktable.h:776
GList * iop
Definition darktable.h:761
struct dt_control_signal_t * signals
Definition darktable.h:774
struct dt_image_cache_t * image_cache
Definition darktable.h:777
struct dt_develop_t * develop
Definition darktable.h:770
struct dt_view_manager_t * view_manager
Definition darktable.h:772
struct dt_control_t * control
Definition darktable.h:773
dt_colorspaces_color_profile_type_t display_type
GHashTable * modules_in_history
Definition develop.c:1344
GHashTable * prev_visible
Definition develop.c:1345
GHashTable * next_visible
Definition develop.c:1346
GHashTable * instance_counts
Definition develop.c:1343
dt_pthread_mutex_t busy_mutex
dt_backbuf_t backbuf
dt_atomic_int shutdown
dt_dev_pixelpipe_type_t type
struct dt_develop_t * dev
void(* list_update)(struct dt_lib_module_t *self)
Definition develop.h:430
int32_t height
Definition develop.h:189
int32_t gui_attached
Definition develop.h:162
GList * iop_order_list
Definition develop.h:285
int undo_history_before_end
Definition develop.h:292
dt_image_t image_storage
Definition develop.h:259
struct dt_develop_t::@19 color_picker
Authoritative darkroom color-picker state.
int32_t orig_height
Definition develop.h:205
struct dt_colorpicker_sample_t * primary_sample
Definition develop.h:391
GList * undo_history_before_snapshot
Definition develop.h:291
gboolean output_inited
Definition develop.h:242
int32_t border_size
Definition develop.h:200
dt_backbuf_t display_histogram
Definition develop.h:337
uint32_t * histogram_pre_levels
Definition develop.h:317
GList * iop
Definition develop.h:279
gboolean request
Definition develop.h:419
int32_t raw_height
Definition develop.h:228
dt_backbuf_t output_histogram
Definition develop.h:336
int32_t preview_height
Definition develop.h:213
int32_t history_end
Definition develop.h:272
struct dt_develop_t::@18 transient_params
GList * undo_history_before_iop_order_list
Definition develop.h:293
gboolean wb_is_D65
Definition develop.h:441
gboolean restrict_histogram
Definition develop.h:396
int32_t processed_width
Definition develop.h:233
void(* list_remove)(struct dt_lib_module_t *self, int formid, int parentid)
Definition develop.h:429
int completed
Definition develop.h:493
struct dt_iop_module_t * gui_module
Definition develop.h:165
dt_pthread_rwlock_t history_mutex
Definition develop.h:263
gboolean live_samples_enabled
Definition develop.h:395
dt_clipping_preview_mode_t mode
Definition develop.h:455
gboolean gui_inited
Definition develop.h:236
struct dt_develop_t::@20::@27 snapshot
int32_t orig_width
Definition develop.h:205
struct dt_lib_module_t *void(* list_change)(struct dt_lib_module_t *self)
Definition develop.h:428
gboolean forms_changed
Definition develop.h:326
float lower
Definition develop.h:453
struct dt_dev_pixelpipe_t * preview_pipe
Definition develop.h:247
gboolean pipelines_started
Definition develop.h:345
GList * history
Definition develop.h:275
int32_t raw_width
Definition develop.h:228
struct dt_dev_pixelpipe_t * virtual_pipe
Definition develop.h:251
GList * allprofile_info
Definition develop.h:314
struct dt_iop_module_t *void * params
Definition develop.h:304
GList * alliop
Definition develop.h:281
dt_aligned_pixel_t wb_coeffs
Definition develop.h:442
dt_dev_overexposed_colorscheme_t colorscheme
Definition develop.h:452
GList * allforms
Definition develop.h:329
dt_backbuf_t raw_histogram
Definition develop.h:335
float scaling
Definition develop.h:193
struct dt_develop_t::@17 roi
struct dt_develop_t::@20::@28 masks
void(* selection_change)(struct dt_lib_module_t *self, struct dt_iop_module_t *module, const int selectid, const int throw_event)
Definition develop.h:432
struct dt_develop_t::@20 proxy
uint32_t * histogram_pre_tonecurve
Definition develop.h:317
uint32_t histogram_pre_levels_max
Definition develop.h:318
int32_t processed_height
Definition develop.h:233
int32_t preview_width
Definition develop.h:213
struct dt_iop_module_t * chroma_adaptation
Definition develop.h:438
gboolean mask_lock
Definition develop.h:497
dt_pthread_mutex_t transient_params_mutex
Definition develop.h:311
dt_pthread_rwlock_t masks_mutex
Definition develop.h:333
uint64_t forms_hash
Definition develop.h:324
struct dt_develop_t::@22 rawoverexposed
const gchar * filename
Definition develop.h:420
uint32_t histogram_pre_tonecurve_max
Definition develop.h:318
float threshold
Definition develop.h:466
struct dt_develop_t::@26 progress
gboolean raw_inited
Definition develop.h:239
struct dt_dev_pixelpipe_t * pipe
Definition develop.h:247
float upper
Definition develop.h:454
int32_t width
Definition develop.h:189
gboolean display_samples
Definition develop.h:394
GList * forms
Definition develop.h:321
int undo_history_depth
Definition develop.h:290
struct dt_develop_t::@21 overexposed
void * blend_params
Definition develop.h:307
float natural_scale
Definition develop.h:224
double ppd
Definition gtk.h:200
struct dt_gui_gtk_t::@47 mouse
float effect_radius
Definition gtk.h:210
float effect_radius_clamped
Definition gtk.h:212
dt_pthread_mutex_t mutex
Definition gtk.h:243
dt_iop_buffer_dsc_t dsc
Definition image.h:337
int32_t id
Definition image.h:319
char multi_name[128]
Definition imageop.h:363
struct dt_develop_t * dev
Definition imageop.h:296
int32_t instance
Definition imageop.h:258
dt_iop_module_so_t * so
Definition imageop.h:359
GtkWidget * expander
Definition imageop.h:345
int request_mask_display
Definition imageop.h:268
Region of interest passed through the pixelpipe.
Definition imageop.h:72
double scale
Definition imageop.h:74
gboolean dt_tag_attach(const guint tagid, const int32_t imgid, const gboolean undo_on, const gboolean group_on)
Definition tags.c:485
gboolean dt_tag_new(const char *name, guint *tagid)
Definition tags.c:179
#define MAX(a, b)
Definition thinplate.c:29
const dt_view_t * dt_view_manager_get_current_view(dt_view_manager_t *vm)
Definition view.c:140
@ DT_VIEW_DARKROOM
Definition view.h:78