Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
pixelpipe_hb.c
Go to the documentation of this file.
1/*
2 This file was part of darktable,
3 This file is part of Ansel,
4 Copyright (C) 2009-2021 darktable developers.
5 Copyright (C) 2023 Aurélien Pierre.
6
7 darktable is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11
12 darktable is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with darktable. If not, see <http://www.gnu.org/licenses/>.
19*/
20#include "common/color_picker.h"
21#include "common/colorspaces.h"
22#include "common/darktable.h"
23#include "common/histogram.h"
24#include "common/imageio.h"
25#include "common/opencl.h"
26#include "common/iop_order.h"
27#include "control/control.h"
28#include "control/conf.h"
29#include "control/signal.h"
30#include "develop/blend.h"
31#include "develop/format.h"
33#include "develop/pixelpipe.h"
34#include "develop/tiling.h"
35#include "develop/masks.h"
36#include "gui/gtk.h"
37#include "libs/colorpicker.h"
38#include "libs/lib.h"
40
41#include <assert.h>
42#include <inttypes.h>
43#include <math.h>
44#include <stdint.h>
45#include <stdlib.h>
46#include <string.h>
47#include <strings.h>
48#include <unistd.h>
49
62
68
70
73
74static char *_pipe_get_pipe_name(int pipe_type)
75{
76 char *r = NULL;
77
78 switch(pipe_type & DT_DEV_PIXELPIPE_ANY)
79 {
81 r = _("PREVIEW");
82 break;
84 r = _("FULL");
85 break;
87 r = _("THUMBNAIL");
88 break;
90 r = _("EXPORT");
91 break;
92 default:
93 r = _("UNKNOWN");
94 }
95 return r;
96}
97
98inline static void _copy_buffer(const char *const restrict input, char *const restrict output,
99 const size_t height, const size_t o_width, const size_t i_width,
100 const size_t x_offset, const size_t y_offset,
101 const size_t stride, const size_t bpp)
102{
103#ifdef _OPENMP
104#pragma omp parallel for default(none) \
105 dt_omp_firstprivate(input, output, bpp, o_width, i_width, height, x_offset, y_offset, stride) \
106 schedule(static)
107#endif
108 for(size_t j = 0; j < height; j++)
109 memcpy(__builtin_assume_aligned(output, 64) + bpp * j * o_width,
110 __builtin_assume_aligned(input, 64) + bpp * (x_offset + (y_offset + j) * i_width),
111 stride);
112}
113
114
115inline static void _uint8_to_float(const uint8_t *const input, float *const output,
116 const size_t width, const size_t height, const size_t chan)
117{
118#ifdef _OPENMP
119#pragma omp parallel for simd default(none) \
120 aligned(input, output: 64) \
121 dt_omp_firstprivate(input, output, width, height, chan) \
122 schedule(static)
123#endif
124 for(size_t k = 0; k < height * width; k++)
125 {
126 const size_t index = k * chan;
127 // Warning: we take BGRa and put it back into RGBa
128 output[index + 0] = (float)input[index + 2] / 255.f;
129 output[index + 1] = (float)input[index + 1] / 255.f;
130 output[index + 2] = (float)input[index + 0] / 255.f;
131 output[index + 3] = 0.f;
132 }
133}
134
135
137 gboolean store_masks)
138{
139 const int res = dt_dev_pixelpipe_init_cached(pipe);
141 pipe->levels = levels;
142 pipe->store_all_raster_masks = store_masks;
143 return res;
144}
145
147{
148 const int res = dt_dev_pixelpipe_init_cached(pipe);
150 return res;
151}
152
154{
155 const int res = dt_dev_pixelpipe_init_cached(pipe);
157 return res;
158}
159
161{
162 // Init with the size of MIPMAP_F
163 const int res = dt_dev_pixelpipe_init_cached(pipe);
165
166 // Needed for caching
168 return res;
169}
170
172{
173 const int res = dt_dev_pixelpipe_init_cached(pipe);
175
176 // Needed for caching
178 return res;
179}
180
182{
183 pipe->devid = -1;
185 pipe->processed_width = pipe->backbuf_width = pipe->iwidth = 0;
186 pipe->processed_height = pipe->backbuf_height = pipe->iheight = 0;
187 pipe->nodes = NULL;
188 pipe->backbuf = NULL;
189
190 pipe->output_backbuf = NULL;
191 pipe->output_backbuf_width = 0;
192 pipe->output_backbuf_height = 0;
194
195 pipe->rawdetail_mask_data = NULL;
197
198 pipe->processing = 0;
199 pipe->running = 0;
201 pipe->opencl_error = 0;
202 pipe->tiling = 0;
204 pipe->bypass_blendif = 0;
205 pipe->input_timestamp = 0;
207 dt_pthread_mutex_init(&(pipe->backbuf_mutex), NULL);
208 dt_pthread_mutex_init(&(pipe->busy_mutex), NULL);
210 pipe->icc_filename = NULL;
212 pipe->iop = NULL;
213 pipe->iop_order_list = NULL;
214 pipe->forms = NULL;
216 pipe->work_profile_info = NULL;
217 pipe->input_profile_info = NULL;
218 pipe->output_profile_info = NULL;
219
221 pipe->last_history_hash = 0;
222 pipe->flush_cache = FALSE;
223 pipe->timeout = 0;
224
226 return 1;
227}
228
231{
232 pipe->iwidth = width;
233 pipe->iheight = height;
234 pipe->imgid = imgid;
235 pipe->image = dev->image_storage;
236 pipe->size = size;
237
239 get_output_format(NULL, pipe, NULL, dev, &pipe->dsc);
240}
241
243 const gchar *icc_filename, dt_iop_color_intent_t icc_intent)
244{
245 pipe->icc_type = icc_type;
246 g_free(pipe->icc_filename);
247 pipe->icc_filename = g_strdup(icc_filename ? icc_filename : "");
248 pipe->icc_intent = icc_intent;
249}
250
252{
254 pipe->backbuf = NULL;
255 // blocks while busy and sets shutdown bit:
257 // so now it's safe to clean up cache:
262 g_free(pipe->icc_filename);
263 pipe->icc_filename = NULL;
264
265 g_free(pipe->output_backbuf);
266 pipe->output_backbuf = NULL;
267 pipe->output_backbuf_width = 0;
268 pipe->output_backbuf_height = 0;
270
272
273 if(pipe->forms)
274 {
275 g_list_free_full(pipe->forms, (void (*)(void *))dt_masks_free_form);
276 pipe->forms = NULL;
277 }
278}
279
280
282{
283 if(pipe->reentry_hash == 0)
284 {
285 pipe->reentry = TRUE;
286 pipe->reentry_hash = hash;
287 dt_print(DT_DEBUG_DEV, "[dev_pixelpipe] re-entry flag set for %" PRIu64 "\n", hash);
288 return TRUE;
289 }
290
291 return FALSE;
292}
293
294
296{
297 if(pipe->reentry_hash == hash)
298 {
299 pipe->reentry = FALSE;
300 pipe->reentry_hash = 0;
301 dt_print(DT_DEBUG_DEV, "[dev_pixelpipe] re-entry flag unset for %" PRIu64 "\n", hash);
302 return TRUE;
303 }
304
305 return FALSE;
306}
307
309{
310 return pipe->reentry;
311}
312
314{
315 pipe->reentry = FALSE;
316 pipe->reentry_hash = 0;
317 pipe->flush_cache = FALSE;
318 dt_print(DT_DEBUG_DEV, "[dev_pixelpipe] re-entry flag reset\n");
319}
320
322{
323 // destroy all nodes
324 for(GList *nodes = pipe->nodes; nodes; nodes = g_list_next(nodes))
325 {
327 // printf("cleanup module `%s'\n", piece->module->name());
328 piece->module->cleanup_pipe(piece->module, pipe, piece);
329 free(piece->blendop_data);
330 piece->blendop_data = NULL;
331 free(piece->histogram);
332 piece->histogram = NULL;
334 free(piece);
335 }
336 g_list_free(pipe->nodes);
337 pipe->nodes = NULL;
338 // also cleanup iop here
339 if(pipe->iop)
340 {
341 g_list_free(pipe->iop);
342 pipe->iop = NULL;
343 }
344 // and iop order
345 g_list_free_full(pipe->iop_order_list, free);
346 pipe->iop_order_list = NULL;
347}
348
350{
351 // check that the pipe was actually properly cleaned up after the last run
352 g_assert(pipe->nodes == NULL);
353 g_assert(pipe->iop == NULL);
354 g_assert(pipe->iop_order_list == NULL);
356
357 // for all modules in dev:
358 // TODO: don't add deprecated modules that are not enabled are not added to pipeline.
359 // currently, that loads 84 modules of which a solid third are not used anymore.
360 // if(module->flags() & IOP_FLAGS_DEPRECATED && !(module->enabled)) continue;
361 pipe->iop = g_list_copy(dev->iop);
362 for(GList *modules = pipe->iop; modules; modules = g_list_next(modules))
363 {
364 dt_iop_module_t *module = (dt_iop_module_t *)modules->data;
366 piece->enabled = module->enabled;
367 piece->request_histogram = DT_REQUEST_ONLY_IN_GUI;
368 piece->histogram_params.roi = NULL;
369 piece->histogram_params.bins_count = 256;
370 piece->histogram_stats.bins_count = 0;
371 piece->histogram_stats.pixels = 0;
372 piece->colors
373 = ((module->default_colorspace(module, pipe, NULL) == IOP_CS_RAW) && (dt_image_is_raw(&pipe->image)))
374 ? 1
375 : 4;
376 piece->iwidth = pipe->iwidth;
377 piece->iheight = pipe->iheight;
378 piece->module = module;
379 piece->pipe = pipe;
380 piece->data = NULL;
381 piece->hash = 0;
382 piece->blendop_hash = 0;
383 piece->global_hash = 0;
384 piece->global_mask_hash = 0;
385 piece->bypass_cache = FALSE;
386 piece->process_cl_ready = 0;
387 piece->process_tiling_ready = 0;
388 piece->raster_masks = dt_pixelpipe_raster_alloc();
389 memset(&piece->processed_roi_in, 0, sizeof(piece->processed_roi_in));
390 memset(&piece->processed_roi_out, 0, sizeof(piece->processed_roi_out));
391
392 // dsc_mask is static, single channel float image
393 memset(&piece->dsc_mask, 0, sizeof(piece->dsc_mask));
394 piece->dsc_mask.channels = 1;
395 piece->dsc_mask.datatype = TYPE_FLOAT;
396 piece->dsc_mask.filters = 0;
397
398 dt_iop_init_pipe(piece->module, pipe, piece);
399 pipe->nodes = g_list_append(pipe->nodes, piece);
400 }
401}
402
404{
405 // Start with a hash that is unique, image-wise.
406 return dt_hash(5381, (const char *)&pipe->image.filename, DT_MAX_FILENAME_LEN);
407}
408
409static uint64_t _node_hash(dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, const dt_iop_roi_t roi_out, const int pos)
410{
411 // to be called at runtime, not at pipe init.
412
413 // Only at the first step of pipe, we don't have a module because we init the base buffer.
414 if(piece)
415 return piece->global_hash;
416 else
417 {
418 // This is used for the first step of the pipe, before modules, when initing base buffer
419 // We need to take care of the ROI manually
420 uint64_t hash = _default_pipe_hash(pipe);
421 hash = dt_hash(hash, (const char *)&roi_out, sizeof(dt_iop_roi_t));
422 return dt_hash(hash, (const char *)&pos, sizeof(int));
423 }
424}
425
427{
428 /* Traverse the pipeline node by node and compute the cumulative (global) hash of each module.
429 * This hash takes into account the hashes of the previous modules and the size of the current ROI.
430 * It is used to map pipeline cache states to current parameters.
431 * It represents the state of internal modules params as well as their position in the pipe and their output size.
432 * It is to be called at pipe init, not at runtime.
433 */
434
435 dt_times_t start;
436 dt_get_times(&start);
437
438 // bernstein hash (djb2)
439 uint64_t hash = _default_pipe_hash(pipe);
440
441 // Bypassing cache contaminates downstream modules, starting at the module requesting it.
442 // Usecase : crop, clip, ashift, etc. that need the uncropped image ;
443 // mask displays ; overexposed/clipping alerts and all other transient previews.
444 gboolean bypass_cache = FALSE;
445
446 for(GList *node = g_list_first(pipe->nodes); node; node = g_list_next(node))
447 {
449 if(!piece->enabled) continue;
450
451 // Combine with the previous bypass states
452 bypass_cache |= piece->module->bypass_cache;
453 piece->bypass_cache = bypass_cache;
454
455 // Combine with the previous modules hashes
456 uint64_t local_hash = piece->hash;
457
458 // Panning and zooming change the ROI. Some GUI modes (crop in editing mode) too.
459 // dt_dev_get_roi_in() should have run before
460 local_hash = dt_hash(local_hash, (const char *)&piece->planned_roi_in, sizeof(dt_iop_roi_t));
461 local_hash = dt_hash(local_hash, (const char *)&piece->planned_roi_out, sizeof(dt_iop_roi_t));
462/*
463 fprintf(stdout, "start->end : %-17s | ROI in: %4ix%-4i @%2.4f | ROI out: %4ix%-4i @%2.4f\n", piece->module->op,
464 piece->buf_in.width, piece->buf_in.height, piece->buf_in.scale, piece->buf_out.width,
465 piece->buf_out.height, piece->buf_out.scale);
466 fprintf(stdout, "end->start : %-17s | ROI in: %4ix%-4i @%2.4f | ROI out: %4ix%-4i @%2.4f\n", piece->module->op,
467 piece->planned_roi_in.width, piece->planned_roi_in.height, piece->planned_roi_in.scale,
468 piece->planned_roi_out.width, piece->planned_roi_out.height, piece->planned_roi_out.scale);
469*/
470 // Mask preview display doesn't re-commit params, so we need to keep that of it here
471 // Too much GUI stuff interleaved with pipeline stuff...
472 // Mask display applies only to main preview in darkroom.
473 if(pipe->type == DT_DEV_PIXELPIPE_FULL)
474 {
475 local_hash = dt_hash(local_hash, (const char *)&piece->module->request_mask_display, sizeof(int));
476 }
477 else
478 {
479 const int zero = 0;
480 local_hash = dt_hash(local_hash, (const char *)&zero, sizeof(int));
481 }
482
483 // Keep track of distortion bypass in GUI. That may affect upstream modules in the stack,
484 // while bypass_cache only affects downstream ones.
485 // In theory, distortion bypass should already affect planned ROI in/out, but it depends whether
486 // internal params are committed. Anyway, make it more reliable.
487 int bypass_distort = dt_dev_pixelpipe_activemodule_disables_currentmodule(dev, piece->module);
488 local_hash = dt_hash(local_hash, (const char *)&bypass_distort, sizeof(int));
489
490 // If the cache bypass is on, the corresponding cache lines will be freed immediately after use,
491 // we need to track that. It somewhat overlaps module->request_mask_display, but...
492 local_hash = dt_hash(local_hash, (const char *)&piece->bypass_cache, sizeof(gboolean));
493
494 // Update global hash for this stage
495 hash = dt_hash(hash, (const char *)&local_hash, sizeof(uint64_t));
496
497 gchar *type = _pipe_get_pipe_name(pipe->type);
498 dt_print(DT_DEBUG_PIPE, "[pixelpipe] global hash for %20s (%s) in pipe %s with hash %lu\n", piece->module->op, piece->module->multi_name, type, (long unsigned int)hash);
499
500 // In case of drawn masks, we would need to account only for the distortions of previous modules.
501 // Aka conditional to: if((piece->module->operation_tags() & IOP_TAG_DISTORT) == IOP_TAG_DISTORT)
502 // But in case of parametric masks, they depend on previous modules parameters.
503 // So, all in all, (parametric | drawn | raster) masking depends on everything :
504 // - if masking on output, internal params + blendop params + all previous modules internal params + ROI size,
505 // - if masking on input, blendop params + all previous modules internal params + ROI size
506 // So we use all that ot once :
507 piece->global_mask_hash = dt_hash(hash, (const char *)&piece->blendop_hash, sizeof(uint64_t));
508
509 // Finally, the output of the module also depends on the mask:
510 hash = dt_hash(hash, (const char *)&piece->global_mask_hash, sizeof(uint64_t));
511 piece->global_hash = hash;
512 }
513
514 dt_show_times(&start, "[dt_pixelpipe_get_global_hash] computing pipe hashes");
515}
516
518{
519 if(piece->module == hist->module)
520 {
521 piece->enabled = hist->enabled;
522 dt_iop_commit_params(hist->module, hist->params, hist->blend_params, pipe, piece);
523
524 if(piece->blendop_data)
525 {
526 const dt_develop_blend_params_t *const bp = (const dt_develop_blend_params_t *)piece->blendop_data;
527 if(bp->details != 0.0f)
529 }
530 return TRUE;
531 }
532 return FALSE;
533}
534
535// helper
537{
538 dt_dev_history_item_t *hist = (dt_dev_history_item_t *)history->data;
539 dt_dev_pixelpipe_iop_t *piece = NULL;
540
541 // Traverse the list of pipe nodes until we found the one matching our history item.
542 // We begin by the end, because it's expected that users will follow an editing history
543 // roughly similar to node order, so as history is growing, we shall have an higher
544 // probability of finding the last history item node at the end of the pipeline.
545 for(GList *nodes = g_list_last(pipe->nodes); nodes; nodes = g_list_previous(nodes))
546 {
547 piece = (dt_dev_pixelpipe_iop_t *)nodes->data;
548 if(_commit_history_to_node(pipe, piece, hist))
549 break;
550 }
551}
552
563void dt_dev_pixelpipe_synch_all_real(dt_dev_pixelpipe_t *pipe, dt_develop_t *dev, const char *caller_func)
564{
565 gchar *type = _pipe_get_pipe_name(pipe->type);
566 dt_print(DT_DEBUG_DEV, "[pixelpipe] synch all modules with history for pipe %s called from %s\n", type, caller_func);
567
568 // go through all history items and adjust params
569 // note that we don't necessarily process the whole history, history_end is an user param.
570 const uint32_t history_end = dt_dev_get_history_end(dev);
571
572 for(GList *nodes = g_list_first(pipe->nodes); nodes; nodes = g_list_next(nodes))
573 {
575 piece->hash = 0;
576 piece->global_hash = 0;
577 piece->enabled = piece->module->default_enabled;
578 gboolean found_history = FALSE;
579
580 // now browse all history items from the end. Since each history item is a full snapshot of parameters,
581 // the latest history entry matching current node is the one we want, and we don't need to look for the previous.
582 for(GList *history = g_list_nth(dev->history, history_end - 1);
583 history;
584 history = g_list_previous(history))
585 {
586 dt_dev_history_item_t *hist = (dt_dev_history_item_t *)history->data;
587 if(_commit_history_to_node(pipe, piece, hist))
588 {
589 found_history = TRUE;
590 break;
591 }
592 }
593
594 // No history found, commit default params if module is enabled by default
595 if(!found_history && piece->enabled)
596 {
597 dt_iop_commit_params(piece->module, piece->module->default_params, piece->module->default_blendop_params,
598 pipe, piece);
599
600 dt_print(DT_DEBUG_PIPE, "[pixelpipe] info: committed default params for %s (%s) in pipe %s \n", piece->module->op, piece->module->multi_name, type);
601 }
602 }
603
604 // Keep track of the last history item to have been synced
605 GList *last_item = g_list_nth(dev->history, history_end - 1);
606 if(last_item)
607 {
608 dt_dev_history_item_t *last_hist = (dt_dev_history_item_t *)last_item->data;
609 pipe->last_history_hash = last_hist->hash;
610 }
611}
612
614{
615 // We can't be sure that there is only one history item to resync
616 // since the last history -> pipe nodes resync: on slow systems,
617 // user may have added more than one during a single pipe recompute.
618 // Note however that the sync_top method is only used when adding new history items
619 // on top. So we need to resync every history item from end to start, until
620 // we find the previously synchronized one. This uses history hashes.
621 gchar *type = _pipe_get_pipe_name(pipe->type);
622
623 dt_print(DT_DEBUG_DEV, "[pixelpipe] synch top modules with history for pipe %s\n", type);
624
625 GList *last_item = g_list_nth(dev->history, dt_dev_get_history_end(dev) - 1);
626 if(last_item)
627 {
628 GList *first_item = NULL;
629 for(GList *history = last_item; history; history = g_list_previous(history))
630 {
631 dt_dev_history_item_t *hist = (dt_dev_history_item_t *)history->data;
632 first_item = history;
633
634 if(hist->hash == pipe->last_history_hash)
635 {
636 // Note that this also takes care of the case where the
637 // last-known history item reference hasn't changed, but its internal
638 // parameters have.
639 break;
640 }
641 // if we don't find the hash again, we will just iterate over the whole history.
642 }
643
644 // We also need to care about the case where the history_end is not at the actual end of the history
645 // aka stop looping before we overflow the desired range of history.
646 GList *fence_item = g_list_nth(dev->history, dt_dev_get_history_end(dev));
647 // if the history end cursor is at the actual end of the history, dt_dev_get_history_end()
648 // returns an index that is outside of the range (equal to number of elements),
649 // so fence_item = NULL but the code works as expected since we check history != NULL
650 // first.
651 for(GList *history = first_item; history && history != fence_item; history = g_list_next(history))
652 {
653 dt_dev_history_item_t *hist = (dt_dev_history_item_t *)history->data;
654 dt_print(DT_DEBUG_DEV, "[pixelpipe] synch top history module `%s` (%s) for pipe %s\n", hist->module->op, hist->module->multi_name, type);
655 dt_dev_pixelpipe_synch(pipe, dev, history);
656 }
657
658 // Keep track of the last history item to have been synced
659 dt_dev_history_item_t *last_hist = (dt_dev_history_item_t *)last_item->data;
660 pipe->last_history_hash = last_hist->hash;
661 }
662 else
663 {
664 dt_print(DT_DEBUG_DEV, "[pixelpipe] synch top history module missing error for pipe %s\n", type);
665 }
666}
667
669{
670 dt_times_t start;
671 dt_get_times(&start);
672
673 // Read and write immediately to ensure cross-thread consistency of the value
674 // in case the GUI overwrites that while we are syncing history and nodes
675 const dt_dev_pixelpipe_change_t status = pipe->changed;
677
678 gchar *type = _pipe_get_pipe_name(pipe->type);
679 char *status_str = g_strdup_printf("%s%s%s%s%s",
680 (status & DT_DEV_PIPE_UNCHANGED) ? "UNCHANGED " : "",
681 (status & DT_DEV_PIPE_REMOVE) ? "REMOVE " : "",
682 (status & DT_DEV_PIPE_TOP_CHANGED) ? "TOP_CHANGED " : "",
683 (status & DT_DEV_PIPE_SYNCH) ? "SYNCH " : "",
684 (status & DT_DEV_PIPE_ZOOMED) ? "ZOOMED " : "");
685
686 dt_print(DT_DEBUG_DEV, "[dt_dev_pixelpipe_change] pipeline state changing for pipe %s, flag %s\n",
687 type, status_str);
688
689 g_free(status_str);
690
691 // mask display off as a starting point
693 // and blendif active
694 pipe->bypass_blendif = 0;
695
696 // Init fucking details masks
697 const dt_image_t *img = &pipe->image;
699 if(dt_image_is_raw(img))
703
705
706 // case DT_DEV_PIPE_UNCHANGED: case DT_DEV_PIPE_ZOOMED:
707 if(status & DT_DEV_PIPE_REMOVE)
708 {
709 // modules have been added in between or removed. need to rebuild the whole pipeline.
713 }
714 else if(status & DT_DEV_PIPE_SYNCH)
715 {
716 // pipeline topology remains intact, only change all params.
718 }
719 else if(status & DT_DEV_PIPE_TOP_CHANGED)
720 {
721 // only top history item(s) changed.
723 }
725
726 dt_show_times_f(&start, "[dt_dev_pixelpipe_change] pipeline resync on the current modules stack", "for pipe %s", type);
727}
728
731{
732 if(module) return module->output_format(module, pipe, piece, dsc);
733
734 // first input.
735 *dsc = pipe->image.buf_dsc;
736
737 if(!(dt_image_is_raw(&pipe->image)))
738 {
739 // image max is normalized before
740 for(int k = 0; k < 4; k++) dsc->processed_maximum[k] = 1.0f;
741 }
742}
743
744
745// helper to get per module histogram
746static void histogram_collect(dt_dev_pixelpipe_iop_t *piece, const void *pixel, const dt_iop_roi_t roi,
747 uint32_t **histogram, uint32_t *histogram_max)
748{
750
751 dt_histogram_roi_t histogram_roi;
752
753 // if the current module does did not specified its own ROI, use the full ROI
754 if(histogram_params.roi == NULL)
755 {
756 histogram_roi = (dt_histogram_roi_t){
757 .width = roi.width, .height = roi.height, .crop_x = 0, .crop_y = 0, .crop_width = 0, .crop_height = 0
758 };
759
760 histogram_params.roi = &histogram_roi;
761 }
762
763 const dt_iop_colorspace_type_t cst = piece->module->input_colorspace(piece->module, piece->pipe, piece);
764
765 dt_histogram_helper(&histogram_params, &piece->histogram_stats, cst, piece->module->histogram_cst, pixel, histogram,
766 piece->module->histogram_middle_grey, dt_ioppr_get_pipe_work_profile_info(piece->pipe));
767 dt_histogram_max_helper(&piece->histogram_stats, cst, piece->module->histogram_cst, histogram, histogram_max);
768}
769
770dt_backbuf_t * _get_backuf(dt_develop_t *dev, const char *op)
771{
772 if(!strcmp(op, "demosaic"))
773 return &dev->raw_histogram;
774 else if(!strcmp(op, "colorout"))
775 return &dev->output_histogram;
776 else if(!strcmp(op, "gamma"))
777 return &dev->display_histogram;
778 else
779 return NULL;
780}
781
783 void *output, const dt_iop_roi_t roi,
785 const uint64_t hash, const size_t bpp)
786{
787 // Runs only on full image but downscaled for perf, aka preview pipe
788 // Not an RGBa float buffer ?
789 if(!(bpp == 4 * sizeof(float))) return;
790
791 dt_backbuf_t *backbuf = _get_backuf(dev, module->op);
792 if(backbuf == NULL) return; // This module is not wired to global histograms
793 if(backbuf->hash == hash) return; // Hash didn't change, nothing to update.
794
795 // Prepare the buffer if needed
796 if(backbuf->buffer == NULL)
797 {
798 // Buffer uninited
799 backbuf->buffer = dt_alloc_align(roi.width * roi.height * bpp);
800 if(backbuf->buffer == NULL)
801 {
802 // Out of memory to allocate. Notify histogram
803 backbuf->hash = -1;
804 return;
805 }
806
807 backbuf->height = roi.height;
808 backbuf->width = roi.width;
809 backbuf->bpp = bpp;
810 }
811 else if((backbuf->height != roi.height) || (backbuf->width != roi.width) || (backbuf->bpp != bpp))
812 {
813 // Cached buffer size doesn't match current one.
814 // There is no reason yet why this should happen because the preview pipe doesn't change size during its lifetime.
815 // But let's future-proof it in case someone gets creative.
816 if(backbuf->buffer) dt_free_align(backbuf->buffer); // maybe write a dt_realloc_align routine ?
817 backbuf->buffer = dt_alloc_align(roi.width * roi.height * bpp);
818 if(backbuf->buffer == NULL)
819 {
820 // Out of memory to allocate. Notify histogram
821 backbuf->hash = -1;
822 return;
823 }
824
825 backbuf->height = roi.height;
826 backbuf->width = roi.width;
827 backbuf->bpp = bpp;
828 }
829
830 if(backbuf->buffer == NULL)
831 {
832 // Out of memory to allocate. Notify histogram
833 backbuf->hash = -1;
834 return;
835 }
836
837 // Integrity hash, mixing interal module params state, and params states of previous modules in pipe.
838 backbuf->hash = hash;
839
840 // Copy to histogram cache
841 dt_times_t start;
842 dt_get_times(&start);
843
844 if(output)
845 _copy_buffer(output, (char *)backbuf->buffer, roi.height, roi.width, roi.width, 0, 0, roi.width * bpp, bpp);
846 else
847 backbuf->hash = -1;
848
849 dt_show_times_f(&start, "[dev_pixelpipe]", "copying global histogram for %s", module->op);
850
851 // That's all. From there, histogram catches the "preview pipeline finished recomputing" signal and redraws if needed.
852 // We don't manage thread locks because there is only one writing point and one reading point, synchronized
853 // through signal & callback.
854
855 // Note that we don't compute the histogram here because, depending on the type of scope requested in GUI,
856 // intermediate color conversions might be needed (vectorscope) or various pixel binnings required (waveform).
857 // Color conversions and binning are deferred to the GUI thread, prior to drawing update.
858}
859
860
861// helper for per-module color picking
862static int pixelpipe_picker_helper(dt_iop_module_t *module, const dt_iop_roi_t roi, dt_aligned_pixel_t picked_color,
863 dt_aligned_pixel_t picked_color_min, dt_aligned_pixel_t picked_color_max,
864 dt_pixelpipe_picker_source_t picker_source, int *box)
865{
866 const float wd = darktable.develop->preview_pipe->backbuf_width;
867 const float ht = darktable.develop->preview_pipe->backbuf_height;
868 const int width = roi.width;
869 const int height = roi.height;
871
872 dt_boundingbox_t fbox = { 0.0f };
873
874 // get absolute pixel coordinates in final preview image
875 if(sample->size == DT_LIB_COLORPICKER_SIZE_BOX)
876 {
877 for(int k = 0; k < 4; k += 2) fbox[k] = sample->box[k] * wd;
878 for(int k = 1; k < 4; k += 2) fbox[k] = sample->box[k] * ht;
879 }
880 else if(sample->size == DT_LIB_COLORPICKER_SIZE_POINT)
881 {
882 fbox[0] = fbox[2] = sample->point[0] * wd;
883 fbox[1] = fbox[3] = sample->point[1] * ht;
884 }
885
886 // transform back to current module coordinates
890
891 fbox[0] -= roi.x;
892 fbox[1] -= roi.y;
893 fbox[2] -= roi.x;
894 fbox[3] -= roi.y;
895
896 // re-order edges of bounding box
897 box[0] = fminf(fbox[0], fbox[2]);
898 box[1] = fminf(fbox[1], fbox[3]);
899 box[2] = fmaxf(fbox[0], fbox[2]);
900 box[3] = fmaxf(fbox[1], fbox[3]);
901
903 {
904 // if we are sampling one point, make sure that we actually sample it.
905 for(int k = 2; k < 4; k++) box[k] += 1;
906 }
907
908 // do not continue if box is completely outside of roi
909 if(box[0] >= width || box[1] >= height || box[2] < 0 || box[3] < 0) return 1;
910
911 // clamp bounding box to roi
912 for(int k = 0; k < 4; k += 2) box[k] = MIN(width - 1, MAX(0, box[k]));
913 for(int k = 1; k < 4; k += 2) box[k] = MIN(height - 1, MAX(0, box[k]));
914
915 // safety check: area needs to have minimum 1 pixel width and height
916 if(box[2] - box[0] < 1 || box[3] - box[1] < 1) return 1;
917
918 return 0;
919}
920
922 const float *pixel, const dt_iop_roi_t roi, float *picked_color,
923 float *picked_color_min, float *picked_color_max,
924 const dt_iop_colorspace_type_t image_cst, dt_pixelpipe_picker_source_t picker_source)
925{
926 int box[4] = { 0 };
927
928 if(pixelpipe_picker_helper(module, roi, picked_color, picked_color_min, picked_color_max, picker_source, box))
929 {
930 for(int k = 0; k < 4; k++)
931 {
932 picked_color_min[k] = INFINITY;
933 picked_color_max[k] = -INFINITY;
934 picked_color[k] = 0.0f;
935 }
936
937 return;
938 }
939
940 dt_aligned_pixel_t min, max, avg;
941 for(int k = 0; k < 4; k++)
942 {
943 min[k] = INFINITY;
944 max[k] = -INFINITY;
945 avg[k] = 0.0f;
946 }
947
949 dt_color_picker_helper(dsc, pixel, &roi, box, avg, min, max, image_cst,
950 dt_iop_color_picker_get_active_cst(module), profile);
951
952 for(int k = 0; k < 4; k++)
953 {
954 picked_color_min[k] = min[k];
955 picked_color_max[k] = max[k];
956 picked_color[k] = avg[k];
957 }
958}
959
960// returns 1 if blend process need the module default colorspace
961static gboolean _transform_for_blend(const dt_iop_module_t *const self, const dt_dev_pixelpipe_iop_t *const piece)
962{
964 if(d)
965 {
966 // check only if blend is active
967 if((self->flags() & IOP_FLAGS_SUPPORTS_BLENDING) && (d->mask_mode != DEVELOP_MASK_DISABLED))
968 {
969 return TRUE;
970 }
971 }
972 return FALSE;
973}
974
976{
977 const dt_iop_colorspace_type_t picker_cst =
979
980 switch(picker_cst)
981 {
982 case IOP_CS_RAW:
983 return IOP_CS_RAW;
984 case IOP_CS_LAB:
985 case IOP_CS_LCH:
986 return IOP_CS_LAB;
987 case IOP_CS_RGB:
988 case IOP_CS_HSL:
989 case IOP_CS_JZCZHZ:
990 return IOP_CS_RGB;
991 case IOP_CS_NONE:
992 // IOP_CS_NONE is used by temperature.c as it may work in RAW or RGB
993 // return the pipe color space to avoid any additional conversions
994 return cst;
995 default:
996 return picker_cst;
997 }
998}
999
1001 float *input, const dt_iop_roi_t roi_in,
1002 dt_iop_buffer_dsc_t *input_format,
1004{
1005 // histogram collection for module
1007 && (piece->request_histogram & DT_REQUEST_ON))
1008 {
1009 const dt_iop_order_iccprofile_info_t *const work_profile
1010 = (input_format->cst != IOP_CS_RAW) ? dt_ioppr_get_pipe_work_profile_info(pipe) : NULL;
1011
1012 // transform to module input colorspace
1013 dt_ioppr_transform_image_colorspace(module, input, input, roi_in.width, roi_in.height, input_format->cst,
1014 module->input_colorspace(module, pipe, piece), &input_format->cst,
1015 work_profile);
1016
1017 histogram_collect(piece, input, roi_in, &(piece->histogram), piece->histogram_max);
1018
1019 if(piece->histogram && (module->request_histogram & DT_REQUEST_ON))
1020 {
1021 const size_t buf_size = 4 * piece->histogram_stats.bins_count * sizeof(uint32_t);
1022 module->histogram = realloc(module->histogram, buf_size);
1023 memcpy(module->histogram, piece->histogram, buf_size);
1024 module->histogram_stats = piece->histogram_stats;
1025 memcpy(module->histogram_max, piece->histogram_max, sizeof(piece->histogram_max));
1026 if(module->widget) dt_control_queue_redraw_widget(module->widget);
1027 }
1028 }
1029 return;
1030}
1031
1032#define KILL_SWITCH_ABORT \
1033 if(dt_atomic_get_int(&pipe->shutdown)) \
1034 { \
1035 if(*cl_mem_output != NULL) \
1036 { \
1037 dt_opencl_release_mem_object(*cl_mem_output); \
1038 *cl_mem_output = NULL; \
1039 } \
1040 dt_iop_nap(5000); \
1041 pipe->status = DT_DEV_PIXELPIPE_DIRTY; \
1042 return 1; \
1043 }
1044
1045// Once we have a cache, stopping computation before full completion
1046// has good chances of leaving it corrupted. So we invalidate it.
1047#define KILL_SWITCH_AND_FLUSH_CACHE \
1048 if(dt_atomic_get_int(&pipe->shutdown)) \
1049 { \
1050 dt_dev_pixelpipe_cache_remove(darktable.pixelpipe_cache, hash, TRUE, output_entry); \
1051 if(*cl_mem_output != NULL) \
1052 { \
1053 dt_opencl_release_mem_object(*cl_mem_output); \
1054 *cl_mem_output = NULL; \
1055 } \
1056 dt_iop_nap(5000); \
1057 pipe->status = DT_DEV_PIXELPIPE_DIRTY; \
1058 return 1; \
1059 }
1060
1062 float *input, dt_iop_buffer_dsc_t *input_format, const dt_iop_roi_t *roi_in,
1063 void **output, dt_iop_buffer_dsc_t **out_format, const dt_iop_roi_t *roi_out,
1066 dt_pixel_cache_entry_t *input_entry)
1067{
1068 // Fetch RGB working profile
1069 // if input is RAW, we can't color convert because RAW is not in a color space
1070 // so we send NULL to by-pass
1071 const dt_iop_order_iccprofile_info_t *const work_profile
1072 = (input_format->cst != IOP_CS_RAW) ? dt_ioppr_get_pipe_work_profile_info(pipe) : NULL;
1073
1074 // transform to module input colorspace
1076 dt_ioppr_transform_image_colorspace(module, input, input, roi_in->width, roi_in->height, input_format->cst,
1077 module->input_colorspace(module, pipe, piece), &input_format->cst,
1078 work_profile);
1080
1081 //fprintf(stdout, "input color space for %s : %i\n", module->op, module->input_colorspace(module, pipe, piece));
1082 const size_t in_bpp = dt_iop_buffer_dsc_to_bpp(input_format);
1083 const size_t bpp = dt_iop_buffer_dsc_to_bpp(*out_format);
1084
1085 const gboolean fitting = dt_tiling_piece_fits_host_memory(MAX(roi_in->width, roi_out->width),
1086 MAX(roi_in->height, roi_out->height), MAX(in_bpp, bpp),
1087 tiling->factor, tiling->overhead);
1088
1089 /* process module on cpu. use tiling if needed and possible. */
1091 if(!fitting && piece->process_tiling_ready)
1092 {
1093 module->process_tiling(module, piece, input, *output, roi_in, roi_out, in_bpp);
1095 *pixelpipe_flow &= ~(PIXELPIPE_FLOW_PROCESSED_ON_GPU);
1096 }
1097 else
1098 {
1099 if(!fitting)
1100 fprintf(stderr, "[pixelpipe_process_on_CPU] Warning: processes `%s' even if memory requirements are not met\n", module->op);
1101
1102 module->process(module, piece, input, *output, roi_in, roi_out);
1103 *pixelpipe_flow |= (PIXELPIPE_FLOW_PROCESSED_ON_CPU);
1105 }
1107
1108 // and save the output colorspace
1109 pipe->dsc.cst = module->output_colorspace(module, pipe, piece);
1110
1111 // blend needs input/output images with default colorspace
1112 if(_transform_for_blend(module, piece))
1113 {
1116 dt_ioppr_transform_image_colorspace(module, input, input, roi_in->width, roi_in->height,
1117 input_format->cst, blend_cst, &input_format->cst,
1118 work_profile);
1120
1121 dt_ioppr_transform_image_colorspace(module, *output, *output, roi_out->width, roi_out->height,
1122 pipe->dsc.cst, blend_cst, &pipe->dsc.cst,
1123 work_profile);
1124 }
1125
1126 /* process blending on CPU */
1127 int err = dt_develop_blend_process(module, piece, input, *output, roi_in, roi_out);
1128 *pixelpipe_flow |= (PIXELPIPE_FLOW_BLENDED_ON_CPU);
1129 *pixelpipe_flow &= ~(PIXELPIPE_FLOW_BLENDED_ON_GPU);
1130
1131 return err; //no errors
1132}
1133
1135{
1136 for(GList *node = g_list_last(pipe->nodes); node; node = g_list_previous(node))
1137 {
1139 if(piece->enabled) return piece;
1140 }
1141
1142 return NULL;
1143}
1144
1145static void _sample_color_picker(dt_dev_pixelpipe_t *pipe, dt_develop_t *dev, float *input,
1146 dt_iop_buffer_dsc_t *input_format, const dt_iop_roi_t roi_in, void **output,
1147 dt_iop_buffer_dsc_t **out_format, const dt_iop_roi_t roi_out,
1149{
1151 && module == dev->gui_module
1152 && dev->gui_module->enabled
1154 return;
1155
1156 // Fetch RGB working profile
1157 // if input is RAW, we can't color convert because RAW is not in a color space
1158 // so we send NULL to by-pass
1159 const dt_iop_order_iccprofile_info_t *const work_profile
1160 = (input_format->cst != IOP_CS_RAW) ? dt_ioppr_get_pipe_work_profile_info(pipe) : NULL;
1161
1162 // ensure that we are using the right color space
1163 dt_iop_colorspace_type_t picker_cst = _transform_for_picker(module, pipe->dsc.cst);
1164 dt_ioppr_transform_image_colorspace(module, input, input, roi_in.width, roi_in.height,
1165 input_format->cst, picker_cst, &input_format->cst,
1166 work_profile);
1167 dt_ioppr_transform_image_colorspace(module, *output, *output, roi_out.width, roi_out.height,
1168 pipe->dsc.cst, picker_cst, &pipe->dsc.cst,
1169 work_profile);
1170
1171 pixelpipe_picker(module, piece, &piece->dsc_in, (float *)input, roi_in, module->picked_color,
1172 module->picked_color_min, module->picked_color_max, input_format->cst, PIXELPIPE_PICKER_INPUT);
1173 pixelpipe_picker(module, piece, &pipe->dsc, (float *)(*output), roi_out, module->picked_output_color,
1176
1178}
1179
1180
1181#ifdef HAVE_OPENCL
1182
1183static void *_gpu_init_buffer(int devid, void *const host_ptr, const dt_iop_roi_t *roi, const size_t bpp,
1184 dt_iop_module_t *module, const char *message)
1185{
1186 // Need to use read-write mode because of in-place color space conversions
1187 void *cl_mem_input = dt_opencl_alloc_device_use_host_pointer(devid, roi->width, roi->height, bpp, host_ptr,
1188 CL_MEM_READ_WRITE | CL_MEM_USE_HOST_PTR);
1189
1190 if(cl_mem_input == NULL)
1191 {
1192 dt_print(DT_DEBUG_OPENCL, "[opencl_pixelpipe] couldn't generate %s buffer for module %s\n", message,
1193 module->op);
1194 }
1195
1196 return cl_mem_input;
1197}
1198
1199
1200static void _gpu_clear_buffer(void **cl_mem_buffer)
1201{
1202 if(*cl_mem_buffer != NULL)
1203 {
1204 dt_opencl_release_mem_object(*cl_mem_buffer);
1205 *cl_mem_buffer = NULL;
1206 }
1207}
1208
1209static gboolean _check_zero_memory(void *cl_mem_pinned, void *host_ptr, dt_iop_module_t *module, const char *message)
1210{
1211 if(cl_mem_pinned == host_ptr)
1212 {
1213 //printf("✅ Zero-copy: GPU is using your host memory directly for %s %s\n", module->op, message);
1214 return TRUE;
1215 }
1216 else
1217 {
1218 printf("❌ Not zero-copy: OpenCL made a temporary device-side copy for %s %s\n", module->op, message);
1219 return FALSE;
1220 }
1221}
1222
1223
1224// mode : CL_MAP_WRITE = copy from host to device, CL_MAP_READ = copy from device to host
1225static int _cl_pinned_memory_copy(const int devid, void *host_ptr, void *cl_mem_buffer, const dt_iop_roi_t *roi,
1226 int cl_mode, size_t bpp, dt_iop_module_t *module, const char *message)
1227{
1228 void *cl_mem_pinned_input = dt_opencl_map_image(devid, cl_mem_buffer, TRUE, cl_mode, roi->width,
1229 roi->height, bpp);
1230 dt_opencl_unmap_mem_object(devid, cl_mem_buffer, cl_mem_pinned_input);
1231
1232 // Map/Unmap synchronizes host <-> device pixels if we have a zero-copy buffer.
1233 // If we couldn't get a zero-copy buffer, we need to manually copy pixels
1234 if(!_check_zero_memory(cl_mem_pinned_input, host_ptr, module, message))
1235 {
1236 cl_int err = CL_SUCCESS;
1237
1238 if(cl_mode == CL_MAP_WRITE)
1239 err = dt_opencl_write_host_to_device(devid, host_ptr, cl_mem_buffer, roi->width, roi->height, bpp);
1240 else if(cl_mode == CL_MAP_READ)
1241 err = dt_opencl_read_host_from_device(devid, host_ptr, cl_mem_buffer, roi->width, roi->height, bpp);
1242
1243 if(err != CL_SUCCESS)
1244 {
1245 dt_print(DT_DEBUG_OPENCL, "[opencl_pixelpipe] couldn't copy image to opencl device for module %s (%s)\n",
1246 module->op, message);
1247 return 1;
1248 }
1249 }
1250
1251 return 0;
1252}
1253
1254
1255static int pixelpipe_process_on_GPU(dt_dev_pixelpipe_t *pipe, dt_develop_t *dev,
1256 float *input, void *cl_mem_input, dt_iop_buffer_dsc_t *input_format, const dt_iop_roi_t *roi_in,
1257 void **output, void **cl_mem_output, dt_iop_buffer_dsc_t **out_format, const dt_iop_roi_t *roi_out,
1260 const size_t in_bpp, const size_t bpp,
1261 dt_pixel_cache_entry_t *input_entry)
1262{
1263 // We don't have OpenCL or we couldn't lock a GPU: fallback to CPU processing
1264 if(!(dt_opencl_is_inited() && pipe->opencl_enabled && pipe->devid >= 0) || input == NULL || *output == NULL)
1265 goto error;
1266
1267 // Fetch RGB working profile
1268 // if input is RAW, we can't color convert because RAW is not in a color space
1269 // so we send NULL to by-pass
1270 const dt_iop_order_iccprofile_info_t *const work_profile
1271 = (input_format->cst != IOP_CS_RAW) ? dt_ioppr_get_pipe_work_profile_info(pipe) : NULL;
1272 gboolean success_opencl = TRUE;
1273 dt_iop_colorspace_type_t input_cst_cl = input_format->cst;
1274
1275 const float required_factor_cl = fmaxf(1.0f, (cl_mem_input != NULL) ? tiling->factor_cl - 1.0f : tiling->factor_cl);
1276 /* pre-check if there is enough space on device for non-tiled processing */
1277 const gboolean fits_on_device = dt_opencl_image_fits_device(pipe->devid, MAX(roi_in->width, roi_out->width),
1278 MAX(roi_in->height, roi_out->height), MAX(in_bpp, bpp),
1279 required_factor_cl, tiling->overhead);
1280
1281 /* general remark: in case of opencl errors within modules or out-of-memory on GPU, we transparently
1282 fall back to the respective cpu module and continue in pixelpipe. If we encounter errors we set
1283 pipe->opencl_error=1, return this function with value 1, and leave appropriate action to the calling
1284 function, which normally would restart pixelpipe without opencl.
1285 Late errors are sometimes detected when trying to get back data from device into host memory and
1286 are treated in the same manner. */
1287
1288 /* test for a possible opencl path after checking some module specific pre-requisites */
1289 gboolean possible_cl = (module->process_cl && piece->process_cl_ready
1290 && !((pipe->type & DT_DEV_PIXELPIPE_PREVIEW) == DT_DEV_PIXELPIPE_PREVIEW
1291 && (module->flags() & IOP_FLAGS_PREVIEW_NON_OPENCL))
1292 && (fits_on_device || piece->process_tiling_ready));
1293
1294 if(possible_cl && !fits_on_device)
1295 {
1296 const float cl_px = dt_opencl_get_device_available(pipe->devid) / (sizeof(float) * MAX(in_bpp, bpp) * ceilf(required_factor_cl));
1297 const float dx = MAX(roi_in->width, roi_out->width);
1298 const float dy = MAX(roi_in->height, roi_out->height);
1299 const float border = tiling->overlap + 1;
1300 /* tests for required gpu mem reflects the different tiling stategies.
1301 simple tiles over whole height or width or inside rectangles where we need at last the overlapping area.
1302 */
1303 const gboolean possible = (cl_px > dx * border) || (cl_px > dy * border) || (cl_px > border * border);
1304 if(!possible)
1305 {
1306 dt_print(DT_DEBUG_OPENCL | DT_DEBUG_TILING, "[dt_dev_pixelpipe_process_rec] CL: tiling impossible in module `%s'. avail=%.1fM, requ=%.1fM (%ix%i). overlap=%i\n",
1307 module->op, cl_px / 1e6f, dx*dy / 1e6f, (int)dx, (int)dy, (int)tiling->overlap);
1308 goto error;
1309 }
1310 }
1311
1312 // Not enough memory for one-shot processing, or no tiling support, or tiling support
1313 // but still not enough memory for tiling (due to boundary overlap).
1314 if(!possible_cl) goto error;
1315
1316 if(fits_on_device)
1317 {
1318 /* image is small enough -> try to directly process entire image with opencl */
1319
1320 /* input is not on gpu memory -> copy it there */
1321 if(cl_mem_input == NULL)
1322 {
1324 cl_mem_input = _gpu_init_buffer(pipe->devid, input, roi_in, in_bpp, module, "input");
1325 int fail = (cl_mem_input == NULL);
1326
1327 if(!fail && _cl_pinned_memory_copy(pipe->devid, input, cl_mem_input, roi_in, CL_MAP_WRITE, in_bpp, module,
1328 "initial input"))
1329 fail = TRUE;
1330
1332
1333 if(fail) goto error;
1334 }
1335
1336 // Allocate GPU memory for output
1337 if(*cl_mem_output == NULL)
1338 {
1339 *cl_mem_output = _gpu_init_buffer(pipe->devid, *output, roi_out, bpp, module, "output");
1340 if(*cl_mem_output == NULL) goto error;
1341 }
1342
1343 // transform to input colorspace if we got our input in a different colorspace
1344 if(!dt_ioppr_transform_image_colorspace_cl(
1345 module, piece->pipe->devid, cl_mem_input, cl_mem_input, roi_in->width, roi_in->height, input_cst_cl,
1346 module->input_colorspace(module, pipe, piece), &input_cst_cl, work_profile))
1347 goto error;
1348
1349 /* now call process_cl of module; module should emit meaningful messages in case of error */
1350 if(!module->process_cl(module, piece, cl_mem_input, *cl_mem_output, roi_in, roi_out))
1351 goto error;
1352
1353 *pixelpipe_flow |= (PIXELPIPE_FLOW_PROCESSED_ON_GPU);
1355
1356 // and save the output colorspace
1357 pipe->dsc.cst = module->output_colorspace(module, pipe, piece);
1358
1359 // blend needs input/output images with default colorspace
1360 if(_transform_for_blend(module, piece))
1361 {
1363 success_opencl &= dt_ioppr_transform_image_colorspace_cl(
1364 module, piece->pipe->devid, cl_mem_input, cl_mem_input, roi_in->width, roi_in->height, input_cst_cl,
1365 blend_cst, &input_cst_cl, work_profile);
1366 success_opencl &= dt_ioppr_transform_image_colorspace_cl(
1367 module, piece->pipe->devid, *cl_mem_output, *cl_mem_output, roi_out->width, roi_out->height,
1368 pipe->dsc.cst, blend_cst, &pipe->dsc.cst, work_profile);
1369
1370 if(!success_opencl)
1371 {
1372 dt_print(DT_DEBUG_OPENCL, "[opencl_pixelpipe] couldn't transform blending colorspace for module %s\n",
1373 module->op);
1374 goto error;
1375 }
1376 }
1377
1378 /* process blending */
1379 if(dt_develop_blend_process_cl(module, piece, cl_mem_input, *cl_mem_output, roi_in, roi_out))
1380 goto error;
1381
1382 *pixelpipe_flow |= (PIXELPIPE_FLOW_BLENDED_ON_GPU);
1383 *pixelpipe_flow &= ~(PIXELPIPE_FLOW_BLENDED_ON_CPU);
1384
1385 // Resync OpenCL output buffer with CPU/RAM cache
1386 if(_cl_pinned_memory_copy(pipe->devid, *output, *cl_mem_output, roi_out, CL_MAP_READ, bpp, module,
1387 "output input"))
1388 goto error;
1389
1390 // Because we color-converted the input several times in place,
1391 // we need to update the colorspace metadata. But since it's shared
1392 // between RAM pixel cache and GPU buffer, then we need to resync GPU buffer with cache.
1393 if(input_format->cst != input_cst_cl)
1394 {
1396 input_format->cst = input_cst_cl;
1397 int fail = _cl_pinned_memory_copy(pipe->devid, input, cl_mem_input, roi_in, CL_MAP_READ, in_bpp, module,
1398 "color-converted input");
1400 if(fail) goto error;
1401 }
1402 }
1403 else if(piece->process_tiling_ready)
1404 {
1405 /* image is too big for direct opencl processing -> try to process image via tiling */
1406 _gpu_clear_buffer(&cl_mem_input);
1407
1408 // transform to module input colorspace
1410 dt_ioppr_transform_image_colorspace(module, input, input, roi_in->width, roi_in->height, input_format->cst,
1411 module->input_colorspace(module, pipe, piece), &input_format->cst,
1412 work_profile);
1414
1415 /* now call process_tiling_cl of module; module should emit meaningful messages in case of error */
1417 int fail = !module->process_tiling_cl(module, piece, input, *output, roi_in, roi_out, in_bpp);
1419
1420 if(fail) goto error;
1421
1423 *pixelpipe_flow &= ~(PIXELPIPE_FLOW_PROCESSED_ON_CPU);
1424
1425 // and save the output colorspace
1426 pipe->dsc.cst = module->output_colorspace(module, pipe, piece);
1427
1428 // blend needs input/output images with default colorspace
1429 if(_transform_for_blend(module, piece))
1430 {
1432
1434 dt_ioppr_transform_image_colorspace(module, input, input, roi_in->width, roi_in->height,
1435 input_format->cst, blend_cst, &input_format->cst,
1436 work_profile);
1438
1439 dt_ioppr_transform_image_colorspace(module, *output, *output, roi_out->width, roi_out->height,
1440 pipe->dsc.cst, blend_cst, &pipe->dsc.cst,
1441 work_profile);
1442 }
1443
1444 /* do process blending on cpu (this is anyhow fast enough) */
1445 dt_develop_blend_process(module, piece, input, *output, roi_in, roi_out);
1446 *pixelpipe_flow |= (PIXELPIPE_FLOW_BLENDED_ON_CPU);
1447 *pixelpipe_flow &= ~(PIXELPIPE_FLOW_BLENDED_ON_GPU);
1448 }
1449 else
1450 {
1451 dt_print(DT_DEBUG_OPENCL, "[opencl_pixelpipe] could not run module '%s' on gpu. falling back to cpu path\n",
1452 module->op);
1453
1454 goto error;
1455 }
1456
1457 // if (rand() % 20 == 0) success_opencl = FALSE; // Test code: simulate spurious failures
1458
1459 // Wait for kernels and copies to complete before accessing the cache again and releasing the locks
1460 dt_opencl_finish(pipe->devid);
1461
1462 // clean up OpenCL input memory and resync pipeline
1463 _gpu_clear_buffer(&cl_mem_input);
1464
1465 // don't free cl_mem_output here, as it will be the input for the next module
1466 // the last module in the pipe will need to be freed by the pipeline process function
1467 return 0;
1468
1469 // any error in OpenCL ends here
1470 // free everything and fall back to CPU processing
1471error:;
1472
1473 dt_opencl_finish(pipe->devid);
1474
1475 _gpu_clear_buffer(cl_mem_output);
1476 _gpu_clear_buffer(&cl_mem_input);
1477
1478 if(input != NULL && *output != NULL)
1479 return pixelpipe_process_on_CPU(pipe, dev, input, input_format, roi_in, output, out_format, roi_out, module,
1480 piece, tiling, pixelpipe_flow, input_entry);
1481 else
1482 return 1;
1483}
1484#endif
1485
1486
1487static void _print_perf_debug(dt_dev_pixelpipe_t *pipe, const dt_pixelpipe_flow_t pixelpipe_flow, dt_dev_pixelpipe_iop_t *piece, dt_iop_module_t *module, dt_times_t *start)
1488{
1489 char histogram_log[32] = "";
1490 if(!(pixelpipe_flow & PIXELPIPE_FLOW_HISTOGRAM_NONE))
1491 {
1492 snprintf(histogram_log, sizeof(histogram_log), ", collected histogram on %s",
1493 (pixelpipe_flow & PIXELPIPE_FLOW_HISTOGRAM_ON_GPU
1494 ? "GPU"
1495 : pixelpipe_flow & PIXELPIPE_FLOW_HISTOGRAM_ON_CPU ? "CPU" : ""));
1496 }
1497
1498 gchar *module_label = dt_history_item_get_name(module);
1500 start, "[dev_pixelpipe]", "processed `%s' on %s%s%s, blended on %s [%s]", module_label,
1501 pixelpipe_flow & PIXELPIPE_FLOW_PROCESSED_ON_GPU
1502 ? "GPU"
1503 : pixelpipe_flow & PIXELPIPE_FLOW_PROCESSED_ON_CPU ? "CPU" : "",
1504 pixelpipe_flow & PIXELPIPE_FLOW_PROCESSED_WITH_TILING ? " with tiling" : "",
1505 (!(pixelpipe_flow & PIXELPIPE_FLOW_HISTOGRAM_NONE) && (piece->request_histogram & DT_REQUEST_ON))
1506 ? histogram_log
1507 : "",
1508 pixelpipe_flow & PIXELPIPE_FLOW_BLENDED_ON_GPU
1509 ? "GPU"
1510 : pixelpipe_flow & PIXELPIPE_FLOW_BLENDED_ON_CPU ? "CPU" : "",
1511 _pipe_get_pipe_name(pipe->type));
1512 g_free(module_label);
1513}
1514
1515
1516static void _print_nan_debug(dt_dev_pixelpipe_t *pipe, void *cl_mem_output, void *output, const dt_iop_roi_t *roi_out, dt_iop_buffer_dsc_t *out_format, dt_iop_module_t *module, const size_t bpp)
1517{
1518 if((darktable.unmuted & DT_DEBUG_NAN) && strcmp(module->op, "gamma") != 0)
1519 {
1520 gchar *module_label = dt_history_item_get_name(module);
1521
1522 if(out_format->datatype == TYPE_FLOAT && out_format->channels == 4)
1523 {
1524 int hasinf = 0, hasnan = 0;
1525 dt_aligned_pixel_t min = { FLT_MAX };
1526 dt_aligned_pixel_t max = { FLT_MIN };
1527
1528 for(int k = 0; k < 4 * roi_out->width * roi_out->height; k++)
1529 {
1530 if((k & 3) < 3)
1531 {
1532 float f = ((float *)(output))[k];
1533 if(isnan(f))
1534 hasnan = 1;
1535 else if(isinf(f))
1536 hasinf = 1;
1537 else
1538 {
1539 min[k & 3] = fmin(f, min[k & 3]);
1540 max[k & 3] = fmax(f, max[k & 3]);
1541 }
1542 }
1543 }
1544 if(hasnan)
1545 fprintf(stderr, "[dev_pixelpipe] module `%s' outputs NaNs! [%s]\n", module_label,
1546 _pipe_get_pipe_name(pipe->type));
1547 if(hasinf)
1548 fprintf(stderr, "[dev_pixelpipe] module `%s' outputs non-finite floats! [%s]\n", module_label,
1549 _pipe_get_pipe_name(pipe->type));
1550 fprintf(stderr, "[dev_pixelpipe] module `%s' min: (%f; %f; %f) max: (%f; %f; %f) [%s]\n", module_label,
1551 min[0], min[1], min[2], max[0], max[1], max[2], _pipe_get_pipe_name(pipe->type));
1552 }
1553 else if(out_format->datatype == TYPE_FLOAT && out_format->channels == 1)
1554 {
1555 int hasinf = 0, hasnan = 0;
1556 float min = FLT_MAX;
1557 float max = FLT_MIN;
1558
1559 for(int k = 0; k < roi_out->width * roi_out->height; k++)
1560 {
1561 float f = ((float *)(output))[k];
1562 if(isnan(f))
1563 hasnan = 1;
1564 else if(isinf(f))
1565 hasinf = 1;
1566 else
1567 {
1568 min = fmin(f, min);
1569 max = fmax(f, max);
1570 }
1571 }
1572 if(hasnan)
1573 fprintf(stderr, "[dev_pixelpipe] module `%s' outputs NaNs! [%s]\n", module_label,
1574 _pipe_get_pipe_name(pipe->type));
1575 if(hasinf)
1576 fprintf(stderr, "[dev_pixelpipe] module `%s' outputs non-finite floats! [%s]\n", module_label,
1577 _pipe_get_pipe_name(pipe->type));
1578 fprintf(stderr, "[dev_pixelpipe] module `%s' min: (%f) max: (%f) [%s]\n", module_label, min, max,
1579 _pipe_get_pipe_name(pipe->type));
1580 }
1581
1582 g_free(module_label);
1583 }
1584}
1585
1586// return 1 on error
1587static int _init_base_buffer(dt_dev_pixelpipe_t *pipe, dt_develop_t *dev, void **output,
1588 void **cl_mem_output, dt_iop_buffer_dsc_t **out_format,
1589 dt_iop_roi_t roi_in, const dt_iop_roi_t roi_out,
1590 const uint64_t hash,
1591 const gboolean bypass_cache,
1592 const size_t bufsize, const size_t bpp)
1593{
1594 // Note: dt_dev_pixelpipe_cache_get actually init/alloc *output
1595 dt_pixel_cache_entry_t *cache_entry;
1596 int new_entry = dt_dev_pixelpipe_cache_get(darktable.pixelpipe_cache, hash, bufsize, "base buffer", pipe->type,
1597 output, out_format, &cache_entry);
1598 if(cache_entry == NULL) return 1;
1599
1600 int err = 0;
1601
1602 if(bypass_cache || new_entry)
1603 {
1604 if(dev->gui_attached)
1605 {
1606 dev->loading_cache = TRUE;
1607 dt_toast_log(_("Loading full-resolution image in cache. This may take some time..."));
1608 }
1609
1610 // Grab input buffer from mipmap cache.
1611 // We will have to copy it here and in pixelpipe cache because it can get evicted from mipmap cache
1612 // anytime after we release the lock, so it would not be thread-safe to just use a reference
1613 // to full-sized buffer. Otherwise, skip dt_dev_pixelpipe_cache_get and
1614 // *output = buf.buf for 1:1 at full resolution.
1617
1618 // Cache size has changed since we inited pipe input ?
1619 // Note: we know pipe->iwidth/iheight are non-zero or we would have not launched a pipe.
1620 // Note 2: there is no valid reason for a cacheline to change size during runtime.
1621 if(!buf.buf || buf.height != pipe->iheight || buf.width != pipe->iwidth || !*output)
1622 {
1623 // Nothing we can do, we need to recompute roi_in and roi_out from scratch
1624 // for all modules with new sizes. Exit on error and catch that in develop.
1626 err = 1;
1627 }
1628 else if(roi_in.scale == 1.0f)
1629 {
1630 // fast branch for 1:1 pixel copies.
1631 // last minute clamping to catch potential out-of-bounds in roi_in and roi_out
1632 const int in_x = MAX(roi_in.x, 0);
1633 const int in_y = MAX(roi_in.y, 0);
1634 const int cp_width = MIN(roi_out.width, pipe->iwidth - in_x);
1635 const int cp_height = MIN(roi_out.height, pipe->iheight - in_y);
1636
1637 if(cp_width > 0 && cp_height > 0)
1638 {
1639 _copy_buffer((const char *const)buf.buf, (char *const)*output, cp_height, roi_out.width,
1640 pipe->iwidth, in_x, in_y, bpp * cp_width, bpp);
1642 err = 0;
1643 }
1644 else
1645 {
1646 // Invalid dimensions
1648 err = 1;
1649 }
1650 }
1651 else
1652 {
1653 fprintf(stdout,
1654 "Base buffer init: scale %f != 1.0 but the input has %li bytes per pixel. This case is not "
1655 "covered by the pipeline, please report the bug.\n",
1656 roi_out.scale, bpp);
1657
1659 err = 1;
1660 }
1661 }
1662 // else found in cache.
1663 if(new_entry)
1664 {
1666 }
1667 return err;
1668}
1669
1670static void _sample_all(dt_dev_pixelpipe_t *pipe, dt_develop_t *dev, void *input, void **output,
1671 const dt_iop_roi_t roi_in, const dt_iop_roi_t roi_out, dt_iop_buffer_dsc_t *input_format,
1673 const uint64_t input_hash, const uint64_t hash, const size_t in_bpp, const size_t bpp,
1674 dt_pixel_cache_entry_t *const input_entry, dt_pixel_cache_entry_t *const output_entry)
1675{
1676 if(!(dev->gui_attached && pipe == dev->preview_pipe
1678 && piece->enabled))
1679 return;
1680
1681 // Lock all buffers in write mode because we might be doing in-place color conversion
1684
1685 // Need to go first because we want module output RGB without color conversion.
1686 // Gamma outputs uint8_t so we take its input. We want float32.
1687 if(strcmp(module->op, "gamma") == 0)
1688 pixelpipe_get_histogram_backbuf(pipe, dev, input, roi_in, module, piece, input_hash, in_bpp);
1689 else
1690 pixelpipe_get_histogram_backbuf(pipe, dev, *output, roi_out, module, piece, hash, bpp);
1691
1692 // sample internal histogram on input and color pickers
1693 collect_histogram_on_CPU(pipe, dev, input, roi_in, input_format, module, piece);
1694 _sample_color_picker(pipe, dev, input, input_format, roi_in, output, output_format, roi_out, module, piece);
1695
1698}
1699
1700
1701// recursive helper for process:
1703 void **cl_mem_output, dt_iop_buffer_dsc_t **out_format,
1704 dt_iop_roi_t roi_out, GList *modules, GList *pieces, int pos)
1705{
1706 // The pipeline is executed recursively, from the end. For each module n, starting from the end,
1707 // if output is cached, take it, else if input is cached, take it, process it and output,
1708 // else recurse to the previous module n-1 to get a an input.
1710
1711 dt_iop_roi_t roi_in = roi_out;
1712
1713 void *input = NULL;
1714 void *cl_mem_input = NULL;
1715 *cl_mem_output = NULL;
1716 dt_iop_module_t *module = NULL;
1717 dt_dev_pixelpipe_iop_t *piece = NULL;
1718
1719 if(modules)
1720 {
1721 module = (dt_iop_module_t *)modules->data;
1722 piece = (dt_dev_pixelpipe_iop_t *)pieces->data;
1723
1724 if(piece)
1725 {
1726 roi_out = piece->planned_roi_out;
1727 roi_in = piece->planned_roi_in;
1728 }
1729
1730 // skip this module?
1731 if(!piece->enabled)
1732 return dt_dev_pixelpipe_process_rec(pipe, dev, output, cl_mem_output, out_format, roi_in,
1733 g_list_previous(modules), g_list_previous(pieces), pos - 1);
1734
1735 if(dev->gui_attached) dev->progress.total++;
1736 }
1737
1739
1740 get_output_format(module, pipe, piece, dev, *out_format);
1741 const size_t bpp = dt_iop_buffer_dsc_to_bpp(*out_format);
1742 const size_t bufsize = (size_t)bpp * roi_out.width * roi_out.height;
1743 uint64_t hash = _node_hash(pipe, piece, roi_out, pos);
1744 const gboolean bypass_cache = (module) ? piece->bypass_cache : FALSE;
1745
1746 // 1) Fast-track:
1747 // If we have a cache entry for this hash, return it straight away,
1748 // don't recurse through pipeline and don't process.
1749 // We can't do it for the preview pipe because it needs to resync
1750 // the global histograms, so we will need to recurse through pipeline anyway.
1751 // This case is handled below.
1752 dt_pixel_cache_entry_t *existing_cache;
1754 && !bypass_cache && !pipe->reentry
1755 && dt_dev_pixelpipe_cache_get_existing(darktable.pixelpipe_cache, hash, output, out_format, &existing_cache))
1756 {
1757 // FIXME: on CPU path and GPU path with tiling, when 2 modules taking different color spaces are back to back,
1758 // the color conversion for the next is done in-place in the output of the previous. We should check
1759 // here if out_format->cst matches wathever we are expecting, and convert back if it doesn't.
1760 dt_print(DT_DEBUG_PIPE, "[dev_pixelpipe] found %" PRIu64 " (%s) for %s pipeline in cache\n", hash, module ? module->op : "noop",
1761 _pipe_get_pipe_name(pipe->type));
1762 return 0;
1763 }
1764
1765 // 2) no module means step 0 of the pipe : importing the input buffer
1766 if(!modules)
1767 {
1768 dt_times_t start;
1769 dt_get_times(&start);
1770
1771 if(_init_base_buffer(pipe, dev, output, cl_mem_output, out_format, roi_in, roi_out, hash, bypass_cache, bufsize,
1772 bpp))
1773 return 1;
1774
1775 dt_show_times_f(&start, "[dev_pixelpipe]", "initing base buffer [%s]", _pipe_get_pipe_name(pipe->type));
1776 return 0;
1777 }
1778
1779 // 3) now recurse through the pipeline.
1780 dt_iop_buffer_dsc_t _input_format = { 0 };
1781 dt_iop_buffer_dsc_t *input_format = &_input_format;
1782
1783 piece = (dt_dev_pixelpipe_iop_t *)pieces->data;
1784 piece->processed_roi_in = roi_in;
1785 piece->processed_roi_out = roi_out;
1786
1787 if(dt_dev_pixelpipe_process_rec(pipe, dev, &input, &cl_mem_input, &input_format, roi_in,
1788 g_list_previous(modules), g_list_previous(pieces), pos - 1))
1789 return 1;
1790
1792
1793 const size_t in_bpp = dt_iop_buffer_dsc_to_bpp(input_format);
1794 piece->dsc_out = piece->dsc_in = *input_format;
1795 module->output_format(module, pipe, piece, &piece->dsc_out);
1796 **out_format = pipe->dsc = piece->dsc_out;
1797 const size_t out_bpp = dt_iop_buffer_dsc_to_bpp(*out_format);
1798
1799 // 3c) actually process this module BUT treat all bypasses first.
1800
1801 // special case: user requests to see channel data in the parametric mask of a module, or the blending
1802 // mask. In that case we skip all modules manipulating pixel content and only process image distorting
1803 // modules. Finally "gamma" is responsible for displaying channel/mask data accordingly.
1804 if(strcmp(module->op, "gamma") != 0
1806 && !(module->operation_tags() & IOP_TAG_DISTORT)
1807 && (in_bpp == out_bpp)
1808 && !memcmp(&roi_in, &roi_out, sizeof(struct dt_iop_roi_t)))
1809 {
1810 // since we're not actually running the module, the output format is the same as the input format
1811 **out_format = pipe->dsc = piece->dsc_out = piece->dsc_in;
1812 *output = input;
1813 return 0;
1814 }
1815
1816 if(dev->gui_attached)
1817 {
1818 gchar *module_label = dt_history_item_get_name(module);
1819 g_free(darktable.main_message);
1820 darktable.main_message = g_strdup_printf(_("Processing module `%s` for pipeline %s (%ix%i px @ %0.f%%)..."),
1821 module_label, _pipe_get_pipe_name(pipe->type),
1822 roi_out.width, roi_out.height, roi_out.scale * 100.f);
1823 g_free(module_label);
1825 }
1826
1827 // Get cache lines for input and output, possibly allocating a new one for output
1828 dt_pixel_cache_entry_t *input_entry = NULL;
1830 if(input_entry == NULL) return 1;
1831
1832 dt_pixel_cache_entry_t *output_entry = NULL;
1833 gchar *type = _pipe_get_pipe_name(pipe->type);
1834 gchar *name = g_strdup_printf("module %s (%s) for pipe %s", module->op, module->multi_name, type);
1835 gboolean new_entry = dt_dev_pixelpipe_cache_get(darktable.pixelpipe_cache, hash, bufsize, name, pipe->type,
1836 output, out_format, &output_entry);
1837 g_free(name);
1838 if(output_entry == NULL) return 1;
1839
1841
1842 // If we found an existing cache entry for this hash (= !new_entry), and
1843 // bypassing the cache is not requested by the pipe, stop before processing.
1844 // This is mostly for the preview pipe since we didn't stop the recursion earlier
1845 // at the last-found cache line.
1846 if(!pipe->reentry && !new_entry && pipe->type == DT_DEV_PIXELPIPE_PREVIEW)
1847 {
1848 dt_print(DT_DEBUG_PIPE, "[pipeline] found %" PRIu64 " (%s) for %s pipeline in cache\n", hash, module ? module->op : "noop", type);
1849
1850 // Sample all color pickers and histograms
1851 _sample_all(pipe, dev, input, output, roi_in, roi_out, input_format, out_format, module,
1852 piece, input_hash, hash, in_bpp, bpp, input_entry, output_entry);
1853
1855
1856 return 0;
1857 }
1858 if(!new_entry)
1859 {
1860 // We have an output cache entry already, lock it for writing
1862 }
1863
1864 /* get tiling requirement of module */
1866 tiling.factor_cl = tiling.maxbuf_cl = -1; // set sentinel value to detect whether callback set sizes
1867 module->tiling_callback(module, piece, &roi_in, &roi_out, &tiling);
1868 if (tiling.factor_cl < 0) tiling.factor_cl = tiling.factor; // default to CPU size if callback didn't set GPU
1869 if (tiling.maxbuf_cl < 0) tiling.maxbuf_cl = tiling.maxbuf;
1870
1871 /* does this module involve blending? */
1872 if(piece->blendop_data && ((dt_develop_blend_params_t *)piece->blendop_data)->mask_mode != DEVELOP_MASK_DISABLED)
1873 {
1874 /* get specific memory requirement for blending */
1875 dt_develop_tiling_t tiling_blendop = { 0 };
1876 tiling_callback_blendop(module, piece, &roi_in, &roi_out, &tiling_blendop);
1877
1878 /* aggregate in structure tiling */
1879 tiling.factor = fmax(tiling.factor, tiling_blendop.factor);
1880 tiling.factor_cl = fmax(tiling.factor_cl, tiling_blendop.factor);
1881 tiling.maxbuf = fmax(tiling.maxbuf, tiling_blendop.maxbuf);
1882 tiling.maxbuf_cl = fmax(tiling.maxbuf_cl, tiling_blendop.maxbuf);
1883 tiling.overhead = fmax(tiling.overhead, tiling_blendop.overhead);
1884 }
1885
1886 /* remark: we do not do tiling for blendop step, neither in opencl nor on cpu. if overall tiling
1887 requirements (maximum of module and blendop) require tiling for opencl path, then following blend
1888 step is anyhow done on cpu. we assume that blending itself will never require tiling in cpu path,
1889 because memory requirements will still be low enough. */
1890
1891 assert(tiling.factor > 0.0f);
1892 assert(tiling.factor_cl > 0.0f);
1893
1894 // Actual pixel processing for this module
1895 int error = 0;
1896 dt_times_t start;
1897 dt_get_times(&start);
1898
1899#ifdef HAVE_OPENCL
1900 error = pixelpipe_process_on_GPU(pipe, dev, input, cl_mem_input, input_format, &roi_in, output, cl_mem_output,
1901 out_format, &roi_out, module, piece, &tiling, &pixelpipe_flow, in_bpp, bpp, input_entry);
1902#else
1903 error = pixelpipe_process_on_CPU(pipe, dev, input, input_format, &roi_in, output, out_format, &roi_out, module,
1904 piece, &tiling, &pixelpipe_flow, input_entry);
1905#endif
1906
1907 _print_perf_debug(pipe, pixelpipe_flow, piece, module, &start);
1908
1909 if(dev->gui_attached) dev->progress.completed++;
1910
1911 // Flag to throw away the output as soon as we are done consuming it in this thread, at the next module.
1912 // Cache bypass is requested by modules like crop/perspective, when they show the full image,
1913 // and when doing anything transient.
1914 if(bypass_cache || pipe->reentry)
1916
1917 // in case we get this buffer from the cache in the future, cache some stuff:
1918 **out_format = piece->dsc_out = pipe->dsc;
1919
1920 // Unlock read and write locks, decrease reference count on input
1923
1924 if(dev->gui_attached)
1925 {
1926 g_free(darktable.main_message);
1927 darktable.main_message = NULL;
1929
1930 if(dev->loading_cache && strcmp(module->op, "initialscale") == 0)
1931 {
1932 dt_toast_log(_("Full-resolution image loaded in cache !"));
1933 dev->loading_cache = FALSE;
1934 }
1935 }
1936
1937 if(error)
1938 {
1939 // No point in keeping garbled output
1942 dt_iop_nap(5000);
1943 return 1;
1944 }
1945
1947
1948 // Sample all color pickers and histograms
1949 _sample_all(pipe, dev, input, output, roi_in, roi_out, input_format, out_format, module, piece, input_hash,
1950 hash, in_bpp, bpp, input_entry, output_entry);
1951
1952 // Print min/max/Nan in debug mode only
1953 if((darktable.unmuted & DT_DEBUG_NAN) && strcmp(module->op, "gamma") != 0)
1954 {
1956 _print_nan_debug(pipe, *cl_mem_output, *output, &roi_out, *out_format, module, bpp);
1958 }
1959
1960 // And throw away the current input if it was flagged before as in the above
1961 // dt_dev_pixel_pipe_cache_auto_destroy_apply(darktable.pixelpipe_cache, input_hash, pipe->type, input_entry);
1962 // Note : for the last module of the pipeline, even if it's flagged for auto_destroy, it will not be
1963 // because it is the input of nothing (but the GUI backbuf). This is by design because we need something
1964 // to paint in UI.
1965
1967
1968 return 0;
1969}
1970
1971
1973{
1974 GList *nodes = g_list_last(pipe->nodes);
1976 while(strcmp(piece->module->op, op))
1977 {
1978 piece->enabled = 0;
1979 piece = NULL;
1980 nodes = g_list_previous(nodes);
1981 if(!nodes) break;
1982 piece = (dt_dev_pixelpipe_iop_t *)nodes->data;
1983 }
1984}
1985
1987{
1988 GList *nodes = pipe->nodes;
1990 while(strcmp(piece->module->op, op))
1991 {
1992 piece->enabled = 0;
1993 piece = NULL;
1994 nodes = g_list_next(nodes);
1995 if(!nodes) break;
1996 piece = (dt_dev_pixelpipe_iop_t *)nodes->data;
1997 }
1998}
1999
2000#define KILL_SWITCH_PIPE \
2001 if(dt_atomic_get_int(&pipe->shutdown)) \
2002 { \
2003 if(pipe->devid >= 0) \
2004 { \
2005 dt_opencl_unlock_device(pipe->devid); \
2006 pipe->devid = -1; \
2007 } \
2008 pipe->status = DT_DEV_PIXELPIPE_DIRTY; \
2009 if(pipe->forms) g_list_free_full(pipe->forms, (void (*)(void *))dt_masks_free_form); \
2010 dt_iop_nap(5000); \
2011 return 1; \
2012 }
2013
2014
2016{
2017 switch(error)
2018 {
2019 case 1:
2020 dt_print(DT_DEBUG_OPENCL, "[opencl] Opencl errors; disabling opencl for %s pipeline!\n", _pipe_get_pipe_name(pipe->type));
2021 dt_control_log(_("Ansel discovered problems with your OpenCL setup; disabling OpenCL for %s pipeline!"), _pipe_get_pipe_name(pipe->type));
2022 break;
2023 case 2:
2025 "[opencl] Too many opencl errors; disabling opencl for this session!\n");
2026 dt_control_log(_("Ansel discovered problems with your OpenCL setup; disabling OpenCL for this session!"));
2027 break;
2028 default:
2029 break;
2030 }
2031}
2032
2033
2035 double scale)
2036{
2038 {
2039 fprintf(stderr, "[memory] before pixelpipe process\n");
2041 }
2042
2044
2045 dt_print(DT_DEBUG_DEV, "[pixelpipe] Started %s pipeline recompute at %i×%i px\n", _pipe_get_pipe_name(pipe->type), width, height);
2046
2047 // get a snapshot of the mask list
2048 pipe->forms = dt_masks_dup_forms_deep(dev->forms, NULL);
2049
2050 // go through the list of modules from the end:
2051 const guint pos = g_list_length(pipe->iop);
2052 GList *modules = g_list_last(pipe->iop);
2053 GList *pieces = g_list_last(pipe->nodes);
2054
2055 // Get the roi_out hash
2056 // Get the previous output size of the module, for cache invalidation.
2057 dt_iop_roi_t roi = (dt_iop_roi_t){ x, y, width, height, scale };
2058 dt_dev_pixelpipe_get_roi_in(pipe, dev, roi);
2060
2061 pipe->backbuf = NULL;
2062 pipe->opencl_enabled = dt_opencl_update_settings(); // update enabled flag and profile from preferences
2063 pipe->devid = (pipe->opencl_enabled) ? dt_opencl_lock_device(pipe->type)
2064 : -1; // try to get/lock opencl resource
2065
2066 if(pipe->devid > -1) dt_opencl_events_reset(pipe->devid);
2067 dt_print(DT_DEBUG_OPENCL, "[pixelpipe_process] [%s] using device %d\n", _pipe_get_pipe_name(pipe->type),
2068 pipe->devid);
2069
2071
2072 gboolean keep_running = TRUE;
2073 int opencl_error = 0;
2074 int err = 0;
2075
2076 while(keep_running)
2077 {
2078
2079#ifdef HAVE_OPENCL
2081#endif
2082
2083 // WARNING: buf will actually be a reference to a pixelpipe cache line, so it will be freed
2084 // when the cache line is flushed or invalidated.
2085 void *buf = NULL;
2086 void *cl_mem_out = NULL;
2087
2088 dt_iop_buffer_dsc_t _out_format = { 0 };
2089 dt_iop_buffer_dsc_t *out_format = &_out_format;
2090
2092
2093 dt_times_t start;
2094 dt_get_times(&start);
2095 err = dt_dev_pixelpipe_process_rec(pipe, dev, &buf, &cl_mem_out, &out_format, roi, modules, pieces, pos);
2096 gchar *msg = g_strdup_printf("[pixelpipe] %s pipeline processing", _pipe_get_pipe_name(pipe->type));
2097 dt_show_times(&start, msg);
2098 g_free(msg);
2099
2100 // The pipeline has copied cl_mem_out into buf, so we can release it now.
2101 #ifdef HAVE_OPENCL
2102 _gpu_clear_buffer(&cl_mem_out);
2103 #endif
2104
2105 // get status summary of opencl queue by checking the eventlist
2106 const int oclerr = (pipe->devid > -1) ? dt_opencl_events_flush(pipe->devid, TRUE) != 0 : 0;
2107
2108 // Relinquish the CPU because we are in a realtime thread
2109 dt_iop_nap(5000);
2110
2111 // Check if we had opencl errors ....
2112 // remark: opencl errors can come in two ways: pipe->opencl_error is TRUE (and err is TRUE) OR oclerr is
2113 // TRUE
2114 keep_running = (oclerr || (err && pipe->opencl_error));
2115 if(keep_running)
2116 {
2117 // Log the error
2118 darktable.opencl->error_count++; // increase error count
2119 opencl_error = 1; // = any OpenCL error, next run goes to CPU
2120
2121 // Disable OpenCL for this pipe
2123 pipe->opencl_enabled = 0;
2124 pipe->opencl_error = 0;
2125 pipe->devid = -1;
2126
2128 {
2129 // Too many errors : dispable OpenCL for this session
2131 dt_capabilities_remove("opencl");
2132 opencl_error = 2; // = too many OpenCL errors, all runs go to CPU
2133 }
2134
2135 _print_opencl_errors(opencl_error, pipe);
2136 }
2137 else if(!dt_atomic_get_int(&pipe->shutdown))
2138 {
2139 // No opencl errors, no killswitch triggered: we should have a valid output buffer now.
2140
2141 // Store the back buffer hash and reference
2142 const dt_dev_pixelpipe_iop_t *last_module = _last_node_in_pipe(pipe);
2143 pipe->backbuf_hash = _node_hash(pipe, last_module, roi, pos);
2144 pipe->backbuf = buf;
2145 pipe->backbuf_width = width;
2146 pipe->backbuf_height = height;
2147
2148 // Note : the last output (backbuf) of the pixelpipe cache is internally locked
2149 // Whatever consuming it will need to unlock it.
2150 }
2151 }
2152
2153 // release resources:
2154 if(pipe->forms)
2155 {
2156 g_list_free_full(pipe->forms, (void (*)(void *))dt_masks_free_form);
2157 pipe->forms = NULL;
2158 }
2159 if(pipe->devid >= 0)
2160 {
2162 pipe->devid = -1;
2163 }
2164
2165 // terminate
2167
2168 // If an intermediate module set that, be sure to reset it at the end
2169 pipe->flush_cache = FALSE;
2170 return err;
2171}
2172
2174{
2175 return (dev // don't segfault
2176 && dev->gui_attached // don't run on background/export pipes
2177 && dev->gui_module // don't segfault
2178 && dev->gui_module != current_module
2179 // current_module is not the active one (capturing edit mode)
2180 && dev->gui_module->operation_tags_filter() & current_module->operation_tags())
2181 // current_module does operation(s) that active module doesn't want
2183 // cache bypass is our hint that the active module is in "editing" mode
2184}
2185
2187 const int width_in, const int height_in,
2188 int *width, int *height)
2189{
2190 dt_iop_roi_t roi_in = (dt_iop_roi_t){ 0, 0, width_in, height_in, 1.0 };
2191 dt_iop_roi_t roi_out;
2192 GList *modules = g_list_first(pipe->iop);
2193 GList *pieces = g_list_first(pipe->nodes);
2194 while(modules)
2195 {
2196 dt_iop_module_t *module = (dt_iop_module_t *)modules->data;
2198
2199 piece->buf_in = roi_in;
2200
2201 // If in GUI and using a module that needs a full, undistorterted image,
2202 // we need to shutdown temporarily any module distorting the image.
2204 piece->enabled = FALSE;
2205
2206 // If module is disabled, modify_roi_in() is a no-op
2207 if(piece->enabled)
2208 module->modify_roi_out(module, piece, &roi_out, &roi_in);
2209 else
2210 roi_out = roi_in;
2211
2212 piece->buf_out = roi_out;
2213 roi_in = roi_out;
2214
2215 modules = g_list_next(modules);
2216 pieces = g_list_next(pieces);
2217 }
2218 *width = roi_out.width;
2219 *height = roi_out.height;
2220}
2221
2222void dt_dev_pixelpipe_get_roi_in(dt_dev_pixelpipe_t *pipe, struct dt_develop_t *dev, const struct dt_iop_roi_t roi_out)
2223{
2224 // while module->modify_roi_out describes how the current module will change the size of
2225 // the output buffer depending on its parameters (pretty intuitive),
2226 // module->modify_roi_in describes "how much material" the current module needs from the previous one,
2227 // because some modules (lens correction) need a padding on their input.
2228 // The tricky part is therefore that the effect of the current module->modify_roi_in() needs to be repercuted
2229 // upstream in the pipeline for proper pipeline cache invalidation, so we need to browse the pipeline
2230 // backwards.
2231
2232 dt_times_t start;
2233 dt_get_times(&start);
2234
2235 dt_iop_roi_t roi_out_temp = roi_out;
2236 dt_iop_roi_t roi_in;
2237 GList *modules = g_list_last(pipe->iop);
2238 GList *pieces = g_list_last(pipe->nodes);
2239 while(modules)
2240 {
2241 dt_iop_module_t *module = (dt_iop_module_t *)modules->data;
2243
2244 piece->planned_roi_out = roi_out_temp;
2245
2246 // If in GUI and using a module that needs a full, undistorterted image,
2247 // we need to shutdown temporarily any module distorting the image.
2249 piece->enabled = FALSE;
2250
2251 // If module is disabled, modify_roi_in() is a no-op
2252 if(piece->enabled)
2253 module->modify_roi_in(module, piece, &roi_out_temp, &roi_in);
2254 else
2255 roi_in = roi_out_temp;
2256
2257 /*
2258 if(piece->enabled)
2259 {
2260 fprintf(stdout, "%s : scale : in %f out %f - (x, y) : (%i, %i) to (%i, %i)\n",
2261 module->op,
2262 roi_in.scale, roi_out.scale,
2263 roi_in.x, roi_in.y,
2264 roi_out.x, roi_out.y);
2265 }
2266 */
2267
2268 piece->planned_roi_in = roi_in;
2269 roi_out_temp = roi_in;
2270
2271 modules = g_list_previous(modules);
2272 pieces = g_list_previous(pieces);
2273 }
2274
2275 dt_show_times(&start, "[dt_pixelpipe_get_roi_in] planning ROI");
2276
2277}
2278
2289 *current_piece, const dt_iop_module_t *target_module)
2290{
2291 gboolean success = TRUE;
2292 gchar *clean_target_name = delete_underscore(target_module->name());
2293 gchar *target_name = g_strdup_printf("%s (%s)", clean_target_name, target_module->multi_name);
2294
2295 if(source_piece == NULL || current_piece == NULL)
2296 {
2297 fprintf(stderr,"[raster masks] ERROR: source: %s, current: %s\n",
2298 (source_piece != NULL) ? "is defined" : "is undefined",
2299 (current_piece != NULL) ? "is definded" : "is undefined");
2300
2301 gchar *hint = NULL;
2302 if(source_piece == NULL)
2303 {
2304 // The loop searching linked modules to the raster masks
2305 // terminated without finding the source module.
2306 // that means the source module has been deleted.
2307 hint = g_strdup_printf(
2308 _("- Check if the module providing the masks for the module %s has not been deleted.\n"),
2309 target_name);
2310 }
2311 else if(current_piece == NULL)
2312 {
2313 // The loop searching linked modules to the raster masks
2314 // has stopped when it finds the source module but before it has
2315 // found the current module:
2316 // That means the raster mask is above current module.
2317 hint = g_strdup_printf(_("- Check if the module %s (%s) providing the masks has not been moved above %s.\n"),
2318 delete_underscore(source_piece->module->name()), source_piece->module->multi_name, clean_target_name);
2319 }
2320
2321 dt_control_log(_("The %s module is trying to reuse a mask from a module but it can't be found.\n"
2322 "\n%s"),
2323 target_name, hint ? hint : "");
2324 g_free(hint);
2325
2326 fprintf(stderr, "[raster masks] no source module for module %s could be found\n", target_name);
2327 success = FALSE;
2328 }
2329
2330 if(success && !source_piece->enabled)
2331 {
2332 gchar *clean_source_name = delete_underscore(source_piece->module->name());
2333 gchar *source_name = g_strdup_printf("%s (%s)", clean_source_name, source_piece->module->multi_name);
2334 // there might be stale masks from disabled modules left over. don't use those!
2335 dt_control_log(_("The `%s` module is trying to reuse a mask from disabled module `%s`.\n"
2336 "Disabled modules cannot provide their masks to other modules.\n"
2337 "\n- Please enable `%s` or change the raster mask in `%s`."),
2338 target_name, source_name, source_name, target_name);
2339
2340 fprintf(stderr, "[raster masks] module %s trying to reuse a mask from disabled instance of %s\n",
2341 target_name, source_name);
2342
2343 g_free(clean_source_name);
2344 g_free(source_name);
2345 success = FALSE;
2346 }
2347
2348 g_free(clean_target_name);
2349 g_free(target_name);
2350 return success;
2351}
2352
2353float *dt_dev_get_raster_mask(dt_dev_pixelpipe_t *pipe, const dt_iop_module_t *raster_mask_source,
2354 const int raster_mask_id, const dt_iop_module_t *target_module,
2355 gboolean *free_mask, int *error)
2356{
2357 if(!error) return NULL;
2358 // TODO: refactor this mess to limit for/if nesting
2359 *error = 0;
2360
2361 gchar *clean_target_name = delete_underscore(target_module->name());
2362 gchar *target_name = g_strdup_printf("%s (%s)", clean_target_name, target_module->multi_name);
2363
2364 if(!raster_mask_source)
2365 {
2366 fprintf(stderr, "[raster masks] The source module of the mask for %s was not found\n", target_name);
2367 g_free(clean_target_name);
2368 g_free(target_name);
2369 return NULL;
2370 }
2371
2372 *free_mask = FALSE;
2373 float *raster_mask = NULL;
2374
2375 // Find the module objects associated with mask provider and consumer
2376 dt_dev_pixelpipe_iop_t *source_piece = NULL;
2377 dt_dev_pixelpipe_iop_t *current_piece = NULL;
2378 GList *source_iter = NULL;
2379 for(source_iter = g_list_last(pipe->nodes); source_iter; source_iter = g_list_previous(source_iter))
2380 {
2381 dt_dev_pixelpipe_iop_t *candidate = (dt_dev_pixelpipe_iop_t *)source_iter->data;
2382 if(candidate->module == target_module)
2383 {
2384 current_piece = candidate;
2385 }
2386 else if(candidate->module == raster_mask_source)
2387 {
2388 source_piece = candidate;
2389 break;
2390 }
2391 }
2392
2393 int err_ret = !_dt_dev_raster_mask_check(source_piece, current_piece, target_module);
2394
2395 // Pass on the error to the returning pointer
2396 *error = err_ret;
2397
2398 if(!err_ret)
2399 {
2400 const uint64_t raster_hash = current_piece->global_mask_hash;
2401
2402 gchar *clean_source_name = delete_underscore(source_piece->module->name());
2403 gchar *source_name = g_strdup_printf("%s (%s)", clean_source_name, source_piece->module->multi_name);
2404 raster_mask = dt_pixelpipe_raster_get(source_piece->raster_masks, raster_mask_id);
2405
2406
2407 // Print debug stuff
2408 gchar *type = _pipe_get_pipe_name(pipe->type);
2409 if(raster_mask)
2410 {
2412 "[raster masks] found in %s mask id %i from %s for module %s in pipe %s with hash %" PRIu64 "\n",
2413 "internal", raster_mask_id, source_name, target_name, type, raster_hash);
2414
2415 // Disable re-entry if any
2416 dt_dev_pixelpipe_unset_reentry(pipe, raster_hash);
2417 }
2418 else
2419 {
2420 fprintf(stderr,
2421 "[raster masks] mask id %i from %s for module %s could not be found in pipe %s. Pipe re-entry will be attempted.\n",
2422 raster_mask_id, source_name, target_name, type);
2423
2424 // Ask for a pipeline re-entry and flush all cache
2425 if(dt_dev_pixelpipe_set_reentry(pipe, raster_hash))
2426 pipe->flush_cache = TRUE;
2427
2428 // This should terminate the pipeline now:
2429 if(error) *error = 1;
2430
2431 g_free(clean_target_name);
2432 g_free(target_name);
2433 return NULL;
2434 }
2435 // If we fetch the raster mask again, straight from its provider, we need to distort it
2436 for(GList *iter = g_list_next(source_iter); iter; iter = g_list_next(iter))
2437 {
2438 // Pass the raster mask through all distortion steps between the provider and the consumer
2439 dt_dev_pixelpipe_iop_t *module = (dt_dev_pixelpipe_iop_t *)iter->data;
2440
2441 if(module->enabled
2442 && !dt_dev_pixelpipe_activemodule_disables_currentmodule(module->module->dev, module->module))
2443 {
2444 if(module->module->distort_mask
2445 && !(!strcmp(module->module->op, "finalscale") // hack against pipes not using finalscale
2446 && module->processed_roi_in.width == 0
2447 && module->processed_roi_in.height == 0))
2448 {
2449 float *transformed_mask = dt_alloc_align_float((size_t)module->processed_roi_out.width
2450 * module->processed_roi_out.height);
2451 if(!transformed_mask)
2452 {
2453 fprintf(stderr, "[raster masks] could not allocate memory for transformed mask\n");
2454 if(error) *error = 1;
2455 g_free(clean_target_name);
2456 g_free(target_name);
2457 return NULL;
2458 }
2459
2460 module->module->distort_mask(module->module,
2461 module,
2462 raster_mask,
2463 transformed_mask,
2464 &module->processed_roi_in,
2465 &module->processed_roi_out);
2466 if(*free_mask) dt_free_align(raster_mask);
2467 *free_mask = TRUE;
2468 raster_mask = transformed_mask;
2469 dt_print(DT_DEBUG_MASKS, "[raster masks] doing transform\n");
2470 }
2471 else if(!module->module->distort_mask &&
2472 (module->processed_roi_in.width != module->processed_roi_out.width ||
2473 module->processed_roi_in.height != module->processed_roi_out.height ||
2474 module->processed_roi_in.x != module->processed_roi_out.x ||
2475 module->processed_roi_in.y != module->processed_roi_out.y))
2476 fprintf(stderr, "FIXME: module `%s' changed the roi from %d x %d @ %d / %d to %d x %d | %d / %d but doesn't have "
2477 "distort_mask() implemented!\n", module->module->op, module->processed_roi_in.width,
2478 module->processed_roi_in.height, module->processed_roi_in.x, module->processed_roi_in.y,
2479 module->processed_roi_out.width, module->processed_roi_out.height, module->processed_roi_out.x,
2480 module->processed_roi_out.y);
2481 }
2482
2483 if(module->module == target_module)
2484 {
2485 dt_print(DT_DEBUG_MASKS, "[raster masks] found mask id %i from %s for module %s (%s) in pipe %s\n",
2486 raster_mask_id, source_name, delete_underscore(module->module->name()),
2487 module->module->multi_name, _pipe_get_pipe_name(pipe->type));
2488 break;
2489 }
2490 }
2491 }
2492
2493 g_free(clean_target_name);
2494 g_free(target_name);
2495 return raster_mask;
2496}
2497
2503
2504gboolean dt_dev_write_rawdetail_mask(dt_dev_pixelpipe_iop_t *piece, float *const rgb, const dt_iop_roi_t *const roi_in, const int mode)
2505{
2506 dt_dev_pixelpipe_t *p = piece->pipe;
2507 if((p->want_detail_mask & DT_DEV_DETAIL_MASK_REQUIRED) == 0)
2508 {
2509 if(p->rawdetail_mask_data)
2511 return FALSE;
2512 }
2513 if((p->want_detail_mask & ~DT_DEV_DETAIL_MASK_REQUIRED) != mode) return FALSE;
2514
2516
2517 const int width = roi_in->width;
2518 const int height = roi_in->height;
2519 float *mask = dt_alloc_align_float((size_t)width * height);
2520 float *tmp = dt_alloc_align_float((size_t)width * height);
2521 if((mask == NULL) || (tmp == NULL)) goto error;
2522
2523 p->rawdetail_mask_data = mask;
2524 memcpy(&p->rawdetail_mask_roi, roi_in, sizeof(dt_iop_roi_t));
2525
2526 dt_aligned_pixel_t wb = { piece->pipe->dsc.temperature.coeffs[0],
2527 piece->pipe->dsc.temperature.coeffs[1],
2528 piece->pipe->dsc.temperature.coeffs[2] };
2529 if((p->want_detail_mask & ~DT_DEV_DETAIL_MASK_REQUIRED) == DT_DEV_DETAIL_MASK_RAWPREPARE)
2530 {
2531 wb[0] = wb[1] = wb[2] = 1.0f;
2532 }
2533 dt_masks_calc_rawdetail_mask(rgb, mask, tmp, width, height, wb);
2534 dt_free_align(tmp);
2535 dt_print(DT_DEBUG_MASKS, "[dt_dev_write_rawdetail_mask] %i (%ix%i)\n", mode, roi_in->width, roi_in->height);
2536 return FALSE;
2537
2538 error:
2539 fprintf(stderr, "[dt_dev_write_rawdetail_mask] couldn't write detail mask\n");
2540 dt_free_align(mask);
2541 dt_free_align(tmp);
2542 return TRUE;
2543}
2544
2545#ifdef HAVE_OPENCL
2546gboolean dt_dev_write_rawdetail_mask_cl(dt_dev_pixelpipe_iop_t *piece, cl_mem in, const dt_iop_roi_t *const roi_in, const int mode)
2547{
2548 dt_dev_pixelpipe_t *p = piece->pipe;
2549 if((p->want_detail_mask & DT_DEV_DETAIL_MASK_REQUIRED) == 0)
2550 {
2551 if(p->rawdetail_mask_data)
2553 return FALSE;
2554 }
2555
2556 if((p->want_detail_mask & ~DT_DEV_DETAIL_MASK_REQUIRED) != mode) return FALSE;
2557
2559
2560 const int width = roi_in->width;
2561 const int height = roi_in->height;
2562
2563 cl_mem out = NULL;
2564 cl_mem tmp = NULL;
2565 float *mask = NULL;
2566 const int devid = p->devid;
2567
2568 cl_int err = CL_SUCCESS;
2570 if(mask == NULL) goto error;
2571 out = dt_opencl_alloc_device(devid, width, height, sizeof(float));
2572 if(out == NULL) goto error;
2573 tmp = dt_opencl_alloc_device_buffer(devid, sizeof(float) * width * height);
2574 if(tmp == NULL) goto error;
2575
2576 {
2577 const int kernel = darktable.opencl->blendop->kernel_calc_Y0_mask;
2578 dt_aligned_pixel_t wb = { piece->pipe->dsc.temperature.coeffs[0],
2579 piece->pipe->dsc.temperature.coeffs[1],
2580 piece->pipe->dsc.temperature.coeffs[2] };
2581 if((p->want_detail_mask & ~DT_DEV_DETAIL_MASK_REQUIRED) == DT_DEV_DETAIL_MASK_RAWPREPARE)
2582 {
2583 wb[0] = wb[1] = wb[2] = 1.0f;
2584 }
2585 size_t sizes[3] = { ROUNDUPDWD(width, devid), ROUNDUPDHT(height, devid), 1 };
2586 dt_opencl_set_kernel_arg(devid, kernel, 0, sizeof(cl_mem), &tmp);
2587 dt_opencl_set_kernel_arg(devid, kernel, 1, sizeof(cl_mem), &in);
2588 dt_opencl_set_kernel_arg(devid, kernel, 2, sizeof(int), &width);
2589 dt_opencl_set_kernel_arg(devid, kernel, 3, sizeof(int), &height);
2590 dt_opencl_set_kernel_arg(devid, kernel, 4, sizeof(float), &wb[0]);
2591 dt_opencl_set_kernel_arg(devid, kernel, 5, sizeof(float), &wb[1]);
2592 dt_opencl_set_kernel_arg(devid, kernel, 6, sizeof(float), &wb[2]);
2593 err = dt_opencl_enqueue_kernel_2d(devid, kernel, sizes);
2594 if(err != CL_SUCCESS) goto error;
2595 }
2596 {
2597 size_t sizes[3] = { ROUNDUPDWD(width, devid), ROUNDUPDHT(height, devid), 1 };
2598 const int kernel = darktable.opencl->blendop->kernel_write_scharr_mask;
2599 dt_opencl_set_kernel_arg(devid, kernel, 0, sizeof(cl_mem), &tmp);
2600 dt_opencl_set_kernel_arg(devid, kernel, 1, sizeof(cl_mem), &out);
2601 dt_opencl_set_kernel_arg(devid, kernel, 2, sizeof(int), &width);
2602 dt_opencl_set_kernel_arg(devid, kernel, 3, sizeof(int), &height);
2603 err = dt_opencl_enqueue_kernel_2d(devid, kernel, sizes);
2604 if(err != CL_SUCCESS) goto error;
2605 }
2606
2607 {
2608 err = dt_opencl_read_host_from_device(devid, mask, out, width, height, sizeof(float));
2609 if(err != CL_SUCCESS) goto error;
2610 }
2611
2612 p->rawdetail_mask_data = mask;
2613 memcpy(&p->rawdetail_mask_roi, roi_in, sizeof(dt_iop_roi_t));
2614
2617 dt_print(DT_DEBUG_MASKS, "[dt_dev_write_rawdetail_mask_cl] mode %i (%ix%i)", mode, roi_in->width, roi_in->height);
2618 return FALSE;
2619
2620 error:
2621 fprintf(stderr, "[dt_dev_write_rawdetail_mask_cl] couldn't write detail mask: %i\n", err);
2625 dt_free_align(mask);
2626 return TRUE;
2627}
2628#endif
2629
2630// this expects a mask prepared by the demosaicer and distorts the mask through all pipeline modules
2631// until target
2632float *dt_dev_distort_detail_mask(const dt_dev_pixelpipe_t *pipe, float *src, const dt_iop_module_t *target_module)
2633{
2634 if(!pipe->rawdetail_mask_data) return NULL;
2635 gboolean valid = FALSE;
2636 const int check = pipe->want_detail_mask & ~DT_DEV_DETAIL_MASK_REQUIRED;
2637
2638 GList *source_iter;
2639 for(source_iter = pipe->nodes; source_iter; source_iter = g_list_next(source_iter))
2640 {
2641 const dt_dev_pixelpipe_iop_t *candidate = (dt_dev_pixelpipe_iop_t *)source_iter->data;
2642 if(((!strcmp(candidate->module->op, "demosaic")) && candidate->enabled) && (check == DT_DEV_DETAIL_MASK_DEMOSAIC))
2643 {
2644 valid = TRUE;
2645 break;
2646 }
2647 if(((!strcmp(candidate->module->op, "rawprepare")) && candidate->enabled) && (check == DT_DEV_DETAIL_MASK_RAWPREPARE))
2648 {
2649 valid = TRUE;
2650 break;
2651 }
2652 }
2653
2654 if(!valid) return NULL;
2655 dt_vprint(DT_DEBUG_MASKS, "[dt_dev_distort_detail_mask] (%ix%i) for module %s\n", pipe->rawdetail_mask_roi.width, pipe->rawdetail_mask_roi.height, target_module->op);
2656
2657 float *resmask = src;
2658 float *inmask = src;
2659 if(source_iter)
2660 {
2661 for(GList *iter = source_iter; iter; iter = g_list_next(iter))
2662 {
2663 dt_dev_pixelpipe_iop_t *module = (dt_dev_pixelpipe_iop_t *)iter->data;
2664 if(module->enabled
2665 && !dt_dev_pixelpipe_activemodule_disables_currentmodule(module->module->dev, module->module))
2666 {
2667 if(module->module->distort_mask
2668 && !(!strcmp(module->module->op, "finalscale") // hack against pipes not using finalscale
2669 && module->processed_roi_in.width == 0
2670 && module->processed_roi_in.height == 0))
2671 {
2672 float *tmp = dt_alloc_align_float((size_t)module->processed_roi_out.width * module->processed_roi_out.height);
2673 dt_vprint(DT_DEBUG_MASKS, " %s %ix%i -> %ix%i\n", module->module->op, module->processed_roi_in.width, module->processed_roi_in.height, module->processed_roi_out.width, module->processed_roi_out.height);
2674 module->module->distort_mask(module->module, module, inmask, tmp, &module->processed_roi_in, &module->processed_roi_out);
2675 resmask = tmp;
2676 if(inmask != src) dt_free_align(inmask);
2677 inmask = tmp;
2678 }
2679 else if(!module->module->distort_mask &&
2680 (module->processed_roi_in.width != module->processed_roi_out.width ||
2681 module->processed_roi_in.height != module->processed_roi_out.height ||
2682 module->processed_roi_in.x != module->processed_roi_out.x ||
2683 module->processed_roi_in.y != module->processed_roi_out.y))
2684 fprintf(stderr, "FIXME: module `%s' changed the roi from %d x %d @ %d / %d to %d x %d | %d / %d but doesn't have "
2685 "distort_mask() implemented!\n", module->module->op, module->processed_roi_in.width,
2686 module->processed_roi_in.height, module->processed_roi_in.x, module->processed_roi_in.y,
2687 module->processed_roi_out.width, module->processed_roi_out.height, module->processed_roi_out.x,
2688 module->processed_roi_out.y);
2689
2690 if(module->module == target_module) break;
2691 }
2692 }
2693 }
2694 return resmask;
2695}
2696
2697// clang-format off
2698// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
2699// vim: shiftwidth=2 expandtab tabstop=2 cindent
2700// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
2701// clang-format on
static void error(char *msg)
Definition ashift_lsd.c:191
#define TRUE
Definition ashift_lsd.c:151
#define FALSE
Definition ashift_lsd.c:147
void dt_atomic_set_int(dt_atomic_int *var, int value)
Definition atomic.h:45
int dt_atomic_get_int(dt_atomic_int *var)
Definition atomic.h:46
int levels(struct dt_imageio_module_data_t *data)
Definition avif.c:685
int width
Definition bilateral.h:1
int height
Definition bilateral.h:1
int dt_develop_blend_process(struct dt_iop_module_t *self, struct dt_dev_pixelpipe_iop_t *piece, const void *const ivoid, void *const ovoid, const struct dt_iop_roi_t *const roi_in, const struct dt_iop_roi_t *const roi_out)
Definition blend.c:450
dt_iop_colorspace_type_t dt_develop_blend_colorspace(const dt_dev_pixelpipe_iop_t *const piece, dt_iop_colorspace_type_t cst)
Definition blend.c:158
void tiling_callback_blendop(struct dt_iop_module_t *self, struct dt_dev_pixelpipe_iop_t *piece, const dt_iop_roi_t *roi_in, const dt_iop_roi_t *roi_out, struct dt_develop_tiling_t *tiling)
Definition blend.c:1387
@ DEVELOP_MASK_DISABLED
Definition blend.h:94
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
dt_iop_colorspace_type_t
Definition color_conversion.h:24
@ IOP_CS_RAW
Definition color_conversion.h:26
@ IOP_CS_LCH
Definition color_conversion.h:29
@ IOP_CS_JZCZHZ
Definition color_conversion.h:31
@ IOP_CS_RGB
Definition color_conversion.h:28
@ IOP_CS_HSL
Definition color_conversion.h:30
@ IOP_CS_LAB
Definition color_conversion.h:27
@ IOP_CS_NONE
Definition color_conversion.h:25
void dt_color_picker_helper(const dt_iop_buffer_dsc_t *dsc, const float *const pixel, const dt_iop_roi_t *roi, const int *const box, dt_aligned_pixel_t picked_color, dt_aligned_pixel_t picked_color_min, dt_aligned_pixel_t picked_color_max, const dt_iop_colorspace_type_t image_cst, const dt_iop_colorspace_type_t picker_cst, const dt_iop_order_iccprofile_info_t *const profile)
Definition color_picker.c:605
dt_iop_colorspace_type_t dt_iop_color_picker_get_active_cst(dt_iop_module_t *module)
Definition color_picker_proxy.c:246
static float kernel(const float *x, const float *y)
Definition colorchecker.c:435
@ DT_LIB_COLORPICKER_SIZE_POINT
Definition colorpicker.h:26
@ DT_LIB_COLORPICKER_SIZE_BOX
Definition colorpicker.h:27
dt_iop_color_intent_t
Definition colorspaces.h:43
@ DT_INTENT_LAST
Definition colorspaces.h:48
dt_colorspaces_color_profile_type_t
Definition colorspaces.h:61
@ DT_COLORSPACE_NONE
Definition colorspaces.h:62
void dt_histogram_max_helper(const dt_dev_histogram_stats_t *const histogram_stats, const dt_iop_colorspace_type_t cst, const dt_iop_colorspace_type_t cst_to, uint32_t **histogram, uint32_t *histogram_max)
Definition common/histogram.c:396
void dt_histogram_helper(dt_dev_histogram_collection_params_t *histogram_params, dt_dev_histogram_stats_t *histogram_stats, const dt_iop_colorspace_type_t cst, const dt_iop_colorspace_type_t cst_to, const void *pixel, uint32_t **histogram, const int compensate_middle_grey, const dt_iop_order_iccprofile_info_t *const profile_info)
Definition common/histogram.c:365
gboolean dt_image_is_rawprepare_supported(const dt_image_t *img)
Definition common/image.c:190
int dt_image_is_raw(const dt_image_t *img)
Definition common/image.c:120
int type
Definition common/metadata.c:42
char * name
Definition common/metadata.c:41
void dt_toast_log(const char *msg,...)
Definition control.c:503
void dt_control_log(const char *msg,...)
Definition control.c:456
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:556
void dt_control_queue_redraw_widget(GtkWidget *widget)
threadsafe request of redraw of specific widget. Use this function if you need to redraw a specific w...
Definition control.c:582
void dt_vprint(dt_debug_thread_t thread, const char *msg,...)
Definition darktable.c:1442
void dt_show_times(const dt_times_t *start, const char *prefix)
Definition darktable.c:1455
darktable_t darktable
Definition darktable.c:111
void dt_print_mem_usage()
Definition darktable.c:1708
void dt_capabilities_remove(char *capability)
Definition darktable.c:1691
void dt_show_times_f(const dt_times_t *start, const char *prefix, const char *suffix,...)
Definition darktable.c:1469
void dt_print(dt_debug_thread_t thread, const char *msg,...)
Definition darktable.c:1417
#define UNKNOWN_IMAGE
Definition darktable.h:139
@ DT_DEBUG_OPENCL
Definition darktable.h:478
@ DT_DEBUG_PIPE
Definition darktable.h:497
@ DT_DEBUG_NAN
Definition darktable.h:482
@ DT_DEBUG_MEMORY
Definition darktable.h:480
@ DT_DEBUG_DEV
Definition darktable.h:474
@ DT_DEBUG_MASKS
Definition darktable.h:483
@ DT_DEBUG_TILING
Definition darktable.h:495
float dt_boundingbox_t[4]
Definition darktable.h:467
static float * dt_alloc_align_float(size_t pixels)
Definition darktable.h:345
static void dt_get_times(dt_times_t *t)
Definition darktable.h:691
static gchar * delete_underscore(const char *s)
Definition darktable.h:843
static uint64_t dt_hash(uint64_t hash, const char *str, size_t size)
Definition darktable.h:803
#define dt_free_align(A)
Definition darktable.h:334
#define DT_MAX_FILENAME_LEN
Definition darktable.h:812
int32_t dt_dev_get_history_end(struct dt_develop_t *dev)
Definition develop.c:1252
size_t dt_iop_buffer_dsc_to_bpp(const struct dt_iop_buffer_dsc_t *dsc)
Definition develop/format.c:22
@ TYPE_FLOAT
Definition develop/format.h:31
int dt_dev_distort_backtransform_plus(dt_develop_t *dev, dt_dev_pixelpipe_t *pipe, const double iop_order, const int transf_direction, float *points, size_t points_count)
Definition develop.c:1088
gchar * dt_history_item_get_name(const struct dt_iop_module_t *module)
Definition develop.c:982
@ DT_DEV_PIXELPIPE_DISPLAY_NONE
Definition develop.h:83
@ DT_DEV_TRANSFORM_DIR_FORW_INCL
Definition develop.h:75
@ DT_DEV_TRANSFORM_DIR_FORW_EXCL
Definition develop.h:76
@ DT_DEV_DETAIL_MASK_DEMOSAIC
Definition develop.h:112
@ DT_DEV_DETAIL_MASK_REQUIRED
Definition develop.h:111
@ DT_DEV_DETAIL_MASK_RAWPREPARE
Definition develop.h:113
@ DT_DEV_DETAIL_MASK_NONE
Definition develop.h:110
static int dt_pthread_mutex_unlock(dt_pthread_mutex_t *mutex) RELEASE(mutex) NO_THREAD_SAFETY_ANALYSIS
Definition dtpthread.h:319
static int dt_pthread_mutex_init(dt_pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr)
Definition dtpthread.h:304
static int dt_pthread_mutex_destroy(dt_pthread_mutex_t *mutex)
Definition dtpthread.h:324
#define dt_pthread_rwlock_unlock
Definition dtpthread.h:337
static int dt_pthread_mutex_lock(dt_pthread_mutex_t *mutex) ACQUIRE(mutex) NO_THREAD_SAFETY_ANALYSIS
Definition dtpthread.h:309
#define dt_pthread_rwlock_rdlock
Definition dtpthread.h:338
static float f(const float t, const float c, const float x)
Definition graduatednd.c:173
int bpp
Definition imageio/format/pdf.c:76
@ IMAGEIO_RGB
Definition imageio.h:55
@ IMAGEIO_INT8
Definition imageio.h:47
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)
Definition imageop.c:1743
void dt_iop_init_pipe(struct dt_iop_module_t *module, struct dt_dev_pixelpipe_t *pipe, struct dt_dev_pixelpipe_iop_t *piece)
Definition imageop.c:467
void dt_iop_nap(int32_t usec)
Definition imageop.c:2452
gboolean dt_iop_get_cache_bypass(dt_iop_module_t *module)
Definition imageop.c:2463
@ DT_REQUEST_COLORPICK_OFF
Definition imageop.h:136
@ IOP_FLAGS_SUPPORTS_BLENDING
Definition imageop.h:108
@ IOP_TAG_DISTORT
Definition imageop.h:92
GList * dt_ioppr_iop_order_copy_deep(GList *iop_order_list)
Definition iop_order.c:1444
__DT_CLONE_TARGETS__ void dt_ioppr_transform_image_colorspace(struct dt_iop_module_t *self, const float *const image_in, float *const image_out, const int width, const int height, const int cst_from, const int cst_to, int *converted_cst, const dt_iop_order_iccprofile_info_t *const profile_info)
Definition iop_profile.c:1017
dt_iop_order_iccprofile_info_t * dt_ioppr_get_pipe_current_profile_info(dt_iop_module_t *module, struct dt_dev_pixelpipe_t *pipe)
Definition iop_profile.c:902
dt_iop_order_iccprofile_info_t * dt_ioppr_get_pipe_work_profile_info(struct dt_dev_pixelpipe_t *pipe)
Definition iop_profile.c:887
GList * dt_masks_dup_forms_deep(GList *forms, dt_masks_form_t *form)
Definition develop/masks/masks.c:68
void dt_masks_free_form(dt_masks_form_t *form)
Definition develop/masks/masks.c:1064
void dt_masks_calc_rawdetail_mask(float *const src, float *const out, float *const tmp, const int width, const int height, const dt_aligned_pixel_t wb)
size_t size
Definition mipmap_cache.c:3
#define dt_mipmap_cache_get(A, B, C, D, E, F)
Definition mipmap_cache.h:110
@ DT_MIPMAP_BLOCKING
Definition mipmap_cache.h:50
#define dt_mipmap_cache_release(A, B)
Definition mipmap_cache.h:132
dt_mipmap_size_t
Definition mipmap_cache.h:30
mask
Definition dtstyle_to_xmp.py:54
str p
Definition extract_wb.py:157
Definition tiling.py:1
static int dt_opencl_enqueue_kernel_2d(const int dev, const int kernel, const size_t *sizes)
Definition opencl.h:560
static size_t dt_opencl_get_device_available(const int devid)
Definition opencl.h:589
static int dt_opencl_set_kernel_arg(const int dev, const int kernel, const size_t size, const void *arg)
Definition opencl.h:556
static void dt_opencl_events_reset(const int devid)
Definition opencl.h:608
static void dt_opencl_unlock_device(const int dev)
Definition opencl.h:524
static int dt_opencl_update_settings(void)
Definition opencl.h:580
static void dt_opencl_check_tuning(const int devid)
Definition opencl.h:593
static int dt_opencl_is_inited(void)
Definition opencl.h:569
#define DT_OPENCL_MAX_ERRORS
Definition opencl.h:30
static int dt_opencl_lock_device(const int dev)
Definition opencl.h:520
static int dt_opencl_events_flush(const int devid, const int reset)
Definition opencl.h:614
static gboolean dt_opencl_image_fits_device(const int devid, const size_t width, const size_t height, const unsigned bpp, const float factor, const size_t overhead)
Definition opencl.h:584
static gboolean dt_opencl_finish(const int devid)
Definition opencl.h:512
static void dt_opencl_release_mem_object(void *mem)
Definition opencl.h:601
float * dt_pixelpipe_raster_get(GHashTable *raster_masks, const int raster_mask_id)
Get the raster mask with given id from the raster masks hashtable of the pixelpipe.
Definition pixelpipe.c:60
void dt_pixelpipe_raster_cleanup(GHashTable *raster_masks)
Definition pixelpipe.c:44
GHashTable * dt_pixelpipe_raster_alloc()
Definition pixelpipe.c:39
@ DT_REQUEST_ON
Definition pixelpipe.h:42
@ DT_REQUEST_ONLY_IN_GUI
Definition pixelpipe.h:43
@ DT_DEV_PIXELPIPE_THUMBNAIL
Definition pixelpipe.h:33
@ DT_DEV_PIXELPIPE_ANY
Definition pixelpipe.h:34
@ DT_DEV_PIXELPIPE_EXPORT
Definition pixelpipe.h:30
@ DT_DEV_PIXELPIPE_PREVIEW
Definition pixelpipe.h:32
@ DT_DEV_PIXELPIPE_FULL
Definition pixelpipe.h:31
int dt_dev_pixelpipe_cache_remove(dt_dev_pixelpipe_cache_t *cache, const uint64_t hash, const gboolean force, dt_pixel_cache_entry_t *cache_entry)
Arbitrarily remove the cache entry matching hash. Entries having a reference count > 0 (inter-thread ...
Definition pixelpipe_cache.c:114
void dt_dev_pixelpipe_cache_ref_count_entry(dt_dev_pixelpipe_cache_t *cache, const uint64_t hash, gboolean lock, dt_pixel_cache_entry_t *cache_entry)
Increase/Decrease the reference count on the cache line as to prevent LRU item removal....
Definition pixelpipe_cache.c:483
void dt_dev_pixelpipe_cache_rdlock_entry(dt_dev_pixelpipe_cache_t *cache, const uint64_t hash, gboolean lock, dt_pixel_cache_entry_t *cache_entry)
Lock or release the read lock on the entry.
Definition pixelpipe_cache.c:514
void dt_dev_pixelpipe_cache_wrlock_entry(dt_dev_pixelpipe_cache_t *cache, const uint64_t hash, gboolean lock, dt_pixel_cache_entry_t *cache_entry)
Lock or release the write lock on the entry.
Definition pixelpipe_cache.c:492
void dt_dev_pixelpipe_cache_print(dt_dev_pixelpipe_cache_t *cache)
Definition pixelpipe_cache.c:564
void dt_dev_pixel_pipe_cache_auto_destroy_apply(dt_dev_pixelpipe_cache_t *cache, const uint64_t hash, const int id, dt_pixel_cache_entry_t *cache_entry)
Definition pixelpipe_cache.c:548
uint64_t dt_dev_pixelpipe_cache_get_hash_data(dt_dev_pixelpipe_cache_t *cache, void *data, dt_pixel_cache_entry_t **entry)
Find the hash of the cache entry holding the buffer data.
Definition pixelpipe_cache.c:435
void dt_dev_pixelpipe_cache_flag_auto_destroy(dt_dev_pixelpipe_cache_t *cache, uint64_t hash, dt_pixel_cache_entry_t *cache_entry)
Flag the cache entry matching hash as "auto_destroy". This is useful for short-lived/disposable cache...
Definition pixelpipe_cache.c:536
int dt_dev_pixelpipe_cache_get_existing(dt_dev_pixelpipe_cache_t *cache, const uint64_t hash, void **data, dt_iop_buffer_dsc_t **dsc, dt_pixel_cache_entry_t **entry)
Get an existing cache line from the cache. This is similar to dt_dev_pixelpipe_cache_get,...
Definition pixelpipe_cache.c:355
int dt_dev_pixelpipe_cache_get(dt_dev_pixelpipe_cache_t *cache, const uint64_t hash, const size_t size, const char *name, const int id, void **data, dt_iop_buffer_dsc_t **dsc, dt_pixel_cache_entry_t **entry)
Get a cache line from the cache.
Definition pixelpipe_cache.c:297
void dt_dev_pixelpipe_disable_before(dt_dev_pixelpipe_t *pipe, const char *op)
Definition pixelpipe_hb.c:1986
int dt_dev_pixelpipe_init_preview(dt_dev_pixelpipe_t *pipe)
Definition pixelpipe_hb.c:160
static void _sample_all(dt_dev_pixelpipe_t *pipe, dt_develop_t *dev, void *input, void **output, const dt_iop_roi_t roi_in, const dt_iop_roi_t roi_out, dt_iop_buffer_dsc_t *input_format, dt_iop_buffer_dsc_t **output_format, dt_iop_module_t *module, dt_dev_pixelpipe_iop_t *piece, const uint64_t input_hash, const uint64_t hash, const size_t in_bpp, const size_t bpp, dt_pixel_cache_entry_t *const input_entry, dt_pixel_cache_entry_t *const output_entry)
Definition pixelpipe_hb.c:1670
void dt_dev_pixelpipe_set_input(dt_dev_pixelpipe_t *pipe, dt_develop_t *dev, int32_t imgid, int width, int height, dt_mipmap_size_t size)
Definition pixelpipe_hb.c:229
static int pixelpipe_picker_helper(dt_iop_module_t *module, const dt_iop_roi_t roi, dt_aligned_pixel_t picked_color, dt_aligned_pixel_t picked_color_min, dt_aligned_pixel_t picked_color_max, dt_pixelpipe_picker_source_t picker_source, int *box)
Definition pixelpipe_hb.c:862
gboolean _commit_history_to_node(dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece, dt_dev_history_item_t *hist)
Definition pixelpipe_hb.c:517
void dt_dev_pixelpipe_reset_reentry(dt_dev_pixelpipe_t *pipe)
Definition pixelpipe_hb.c:313
static dt_iop_colorspace_type_t _transform_for_picker(dt_iop_module_t *self, const dt_iop_colorspace_type_t cst)
Definition pixelpipe_hb.c:975
int dt_dev_pixelpipe_init_cached(dt_dev_pixelpipe_t *pipe)
Definition pixelpipe_hb.c:181
static void pixelpipe_picker(dt_iop_module_t *module, dt_dev_pixelpipe_iop_t *piece, dt_iop_buffer_dsc_t *dsc, const float *pixel, const dt_iop_roi_t roi, float *picked_color, float *picked_color_min, float *picked_color_max, const dt_iop_colorspace_type_t image_cst, dt_pixelpipe_picker_source_t picker_source)
Definition pixelpipe_hb.c:921
void dt_dev_pixelpipe_get_roi_out(dt_dev_pixelpipe_t *pipe, struct dt_develop_t *dev, const int width_in, const int height_in, int *width, int *height)
Definition pixelpipe_hb.c:2186
gboolean dt_dev_pixelpipe_has_reentry(dt_dev_pixelpipe_t *pipe)
Definition pixelpipe_hb.c:308
float * dt_dev_distort_detail_mask(const dt_dev_pixelpipe_t *pipe, float *src, const dt_iop_module_t *target_module)
Definition pixelpipe_hb.c:2632
dt_pixelpipe_flow_t
Definition pixelpipe_hb.c:51
@ PIXELPIPE_FLOW_HISTOGRAM_ON_GPU
Definition pixelpipe_hb.c:55
@ PIXELPIPE_FLOW_HISTOGRAM_NONE
Definition pixelpipe_hb.c:53
@ PIXELPIPE_FLOW_PROCESSED_ON_CPU
Definition pixelpipe_hb.c:56
@ PIXELPIPE_FLOW_PROCESSED_WITH_TILING
Definition pixelpipe_hb.c:58
@ PIXELPIPE_FLOW_PROCESSED_ON_GPU
Definition pixelpipe_hb.c:57
@ PIXELPIPE_FLOW_NONE
Definition pixelpipe_hb.c:52
@ PIXELPIPE_FLOW_BLENDED_ON_CPU
Definition pixelpipe_hb.c:59
@ PIXELPIPE_FLOW_HISTOGRAM_ON_CPU
Definition pixelpipe_hb.c:54
@ PIXELPIPE_FLOW_BLENDED_ON_GPU
Definition pixelpipe_hb.c:60
void dt_dev_pixelpipe_synch_top(dt_dev_pixelpipe_t *pipe, dt_develop_t *dev)
Definition pixelpipe_hb.c:613
gboolean dt_dev_write_rawdetail_mask(dt_dev_pixelpipe_iop_t *piece, float *const rgb, const dt_iop_roi_t *const roi_in, const int mode)
Definition pixelpipe_hb.c:2504
void dt_dev_pixelpipe_disable_after(dt_dev_pixelpipe_t *pipe, const char *op)
Definition pixelpipe_hb.c:1972
void dt_dev_pixelpipe_synch_all_real(dt_dev_pixelpipe_t *pipe, dt_develop_t *dev, const char *caller_func)
Find the last history item matching each pipeline node (module), in the order of pipeline execution....
Definition pixelpipe_hb.c:563
dt_backbuf_t * _get_backuf(dt_develop_t *dev, const char *op)
Definition pixelpipe_hb.c:770
static void _print_perf_debug(dt_dev_pixelpipe_t *pipe, const dt_pixelpipe_flow_t pixelpipe_flow, dt_dev_pixelpipe_iop_t *piece, dt_iop_module_t *module, dt_times_t *start)
Definition pixelpipe_hb.c:1487
void dt_dev_pixelpipe_synch(dt_dev_pixelpipe_t *pipe, dt_develop_t *dev, GList *history)
Definition pixelpipe_hb.c:536
dt_pixelpipe_picker_source_t
Definition pixelpipe_hb.c:64
@ PIXELPIPE_PICKER_INPUT
Definition pixelpipe_hb.c:65
@ PIXELPIPE_PICKER_OUTPUT
Definition pixelpipe_hb.c:66
static gboolean _transform_for_blend(const dt_iop_module_t *const self, const dt_dev_pixelpipe_iop_t *const piece)
Definition pixelpipe_hb.c:961
static gboolean _dt_dev_raster_mask_check(dt_dev_pixelpipe_iop_t *source_piece, dt_dev_pixelpipe_iop_t *current_piece, const dt_iop_module_t *target_module)
Checks the validity of the raster mask source and target modules, outputs errors if necessary....
Definition pixelpipe_hb.c:2288
static void _print_nan_debug(dt_dev_pixelpipe_t *pipe, void *cl_mem_output, void *output, const dt_iop_roi_t *roi_out, dt_iop_buffer_dsc_t *out_format, dt_iop_module_t *module, const size_t bpp)
Definition pixelpipe_hb.c:1516
#define KILL_SWITCH_ABORT
Definition pixelpipe_hb.c:1032
void dt_dev_pixelpipe_set_icc(dt_dev_pixelpipe_t *pipe, dt_colorspaces_color_profile_type_t icc_type, const gchar *icc_filename, dt_iop_color_intent_t icc_intent)
Definition pixelpipe_hb.c:242
void dt_dev_pixelpipe_create_nodes(dt_dev_pixelpipe_t *pipe, dt_develop_t *dev)
Definition pixelpipe_hb.c:349
static char * _pipe_get_pipe_name(int pipe_type)
Definition pixelpipe_hb.c:74
static void _print_opencl_errors(int error, dt_dev_pixelpipe_t *pipe)
Definition pixelpipe_hb.c:2015
static int dt_dev_pixelpipe_process_rec(dt_dev_pixelpipe_t *pipe, dt_develop_t *dev, void **output, void **cl_mem_output, dt_iop_buffer_dsc_t **out_format, dt_iop_roi_t roi_out, GList *modules, GList *pieces, int pos)
Definition pixelpipe_hb.c:1702
static dt_dev_pixelpipe_iop_t * _last_node_in_pipe(dt_dev_pixelpipe_t *pipe)
Definition pixelpipe_hb.c:1134
int dt_dev_pixelpipe_init_export(dt_dev_pixelpipe_t *pipe, int32_t width, int32_t height, int levels, gboolean store_masks)
Definition pixelpipe_hb.c:136
static void collect_histogram_on_CPU(dt_dev_pixelpipe_t *pipe, dt_develop_t *dev, float *input, const dt_iop_roi_t roi_in, dt_iop_buffer_dsc_t *input_format, dt_iop_module_t *module, dt_dev_pixelpipe_iop_t *piece)
Definition pixelpipe_hb.c:1000
void dt_dev_pixelpipe_get_roi_in(dt_dev_pixelpipe_t *pipe, struct dt_develop_t *dev, const struct dt_iop_roi_t roi_out)
Definition pixelpipe_hb.c:2222
static uint64_t _node_hash(dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, const dt_iop_roi_t roi_out, const int pos)
Definition pixelpipe_hb.c:409
static void pixelpipe_get_histogram_backbuf(dt_dev_pixelpipe_t *pipe, dt_develop_t *dev, void *output, const dt_iop_roi_t roi, dt_iop_module_t *module, dt_dev_pixelpipe_iop_t *piece, const uint64_t hash, const size_t bpp)
Definition pixelpipe_hb.c:782
static int pixelpipe_process_on_CPU(dt_dev_pixelpipe_t *pipe, dt_develop_t *dev, float *input, dt_iop_buffer_dsc_t *input_format, const dt_iop_roi_t *roi_in, void **output, dt_iop_buffer_dsc_t **out_format, const dt_iop_roi_t *roi_out, dt_iop_module_t *module, dt_dev_pixelpipe_iop_t *piece, dt_develop_tiling_t *tiling, dt_pixelpipe_flow_t *pixelpipe_flow, dt_pixel_cache_entry_t *input_entry)
Definition pixelpipe_hb.c:1061
int dt_dev_pixelpipe_init_dummy(dt_dev_pixelpipe_t *pipe, int32_t width, int32_t height)
Definition pixelpipe_hb.c:153
static void get_output_format(dt_iop_module_t *module, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece, dt_develop_t *dev, dt_iop_buffer_dsc_t *dsc)
Definition pixelpipe_hb.c:729
static void histogram_collect(dt_dev_pixelpipe_iop_t *piece, const void *pixel, const dt_iop_roi_t roi, uint32_t **histogram, uint32_t *histogram_max)
Definition pixelpipe_hb.c:746
float * dt_dev_get_raster_mask(dt_dev_pixelpipe_t *pipe, const dt_iop_module_t *raster_mask_source, const int raster_mask_id, const dt_iop_module_t *target_module, gboolean *free_mask, int *error)
Definition pixelpipe_hb.c:2353
static uint64_t _default_pipe_hash(dt_dev_pixelpipe_t *pipe)
Definition pixelpipe_hb.c:403
#define KILL_SWITCH_PIPE
Definition pixelpipe_hb.c:2000
void dt_dev_pixelpipe_cleanup(dt_dev_pixelpipe_t *pipe)
Definition pixelpipe_hb.c:251
gboolean dt_dev_pixelpipe_unset_reentry(dt_dev_pixelpipe_t *pipe, uint64_t hash)
Remove the re-entry pipeline flag, only if the object identifier is the one that set it....
Definition pixelpipe_hb.c:295
static void _sample_color_picker(dt_dev_pixelpipe_t *pipe, dt_develop_t *dev, float *input, dt_iop_buffer_dsc_t *input_format, const dt_iop_roi_t roi_in, void **output, dt_iop_buffer_dsc_t **out_format, const dt_iop_roi_t roi_out, dt_iop_module_t *module, dt_dev_pixelpipe_iop_t *piece)
Definition pixelpipe_hb.c:1145
static void _copy_buffer(const char *const restrict input, char *const restrict output, const size_t height, const size_t o_width, const size_t i_width, const size_t x_offset, const size_t y_offset, const size_t stride, const size_t bpp)
Definition pixelpipe_hb.c:98
gboolean dt_dev_pixelpipe_activemodule_disables_currentmodule(struct dt_develop_t *dev, struct dt_iop_module_t *current_module)
Definition pixelpipe_hb.c:2173
int dt_dev_pixelpipe_init_thumbnail(dt_dev_pixelpipe_t *pipe, int32_t width, int32_t height)
Definition pixelpipe_hb.c:146
int dt_dev_pixelpipe_init(dt_dev_pixelpipe_t *pipe)
Definition pixelpipe_hb.c:171
static void _uint8_to_float(const uint8_t *const input, float *const output, const size_t width, const size_t height, const size_t chan)
Definition pixelpipe_hb.c:115
static int _init_base_buffer(dt_dev_pixelpipe_t *pipe, dt_develop_t *dev, void **output, void **cl_mem_output, dt_iop_buffer_dsc_t **out_format, dt_iop_roi_t roi_in, const dt_iop_roi_t roi_out, const uint64_t hash, const gboolean bypass_cache, const size_t bufsize, const size_t bpp)
Definition pixelpipe_hb.c:1587
#define KILL_SWITCH_AND_FLUSH_CACHE
Definition pixelpipe_hb.c:1047
gboolean dt_dev_pixelpipe_set_reentry(dt_dev_pixelpipe_t *pipe, uint64_t hash)
Set the re-entry pipeline flag, only if no object is already capturing it. Re-entered pipelines run w...
Definition pixelpipe_hb.c:281
void dt_dev_pixelpipe_change(dt_dev_pixelpipe_t *pipe, struct dt_develop_t *dev)
Definition pixelpipe_hb.c:668
void dt_pixelpipe_get_global_hash(dt_dev_pixelpipe_t *pipe, dt_develop_t *dev)
Definition pixelpipe_hb.c:426
void dt_dev_clear_rawdetail_mask(dt_dev_pixelpipe_t *pipe)
Definition pixelpipe_hb.c:2498
int dt_dev_pixelpipe_process(dt_dev_pixelpipe_t *pipe, dt_develop_t *dev, int x, int y, int width, int height, double scale)
Definition pixelpipe_hb.c:2034
void dt_dev_pixelpipe_cleanup_nodes(dt_dev_pixelpipe_t *pipe)
Definition pixelpipe_hb.c:321
dt_dev_pixelpipe_change_t
Definition pixelpipe_hb.h:102
@ DT_DEV_PIPE_ZOOMED
Definition pixelpipe_hb.h:108
@ DT_DEV_PIPE_SYNCH
Definition pixelpipe_hb.h:106
@ DT_DEV_PIPE_TOP_CHANGED
Definition pixelpipe_hb.h:104
@ DT_DEV_PIPE_REMOVE
Definition pixelpipe_hb.h:105
@ DT_DEV_PIPE_UNCHANGED
Definition pixelpipe_hb.h:103
#define dt_dev_pixelpipe_synch_all(pipe, dev)
Definition pixelpipe_hb.h:291
@ DT_DEV_PIXELPIPE_DIRTY
Definition pixelpipe_hb.h:113
void output_format(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece, dt_iop_buffer_dsc_t *dsc)
Definition rawprepare.c:265
#define DT_DEBUG_CONTROL_SIGNAL_RAISE(ctlsig, signal,...)
Definition signal.h:276
@ DT_SIGNAL_CONTROL_PICKERDATA_READY
This signal is raised when new color picker data are available in the pixelpipe. 1 module 2 piece no ...
Definition signal.h:229
unsigned __int64 uint64_t
Definition strptime.c:71
struct dt_lib_t * lib
Definition darktable.h:537
struct dt_dev_pixelpipe_cache_t * pixelpipe_cache
Definition darktable.h:556
struct dt_mipmap_cache_t * mipmap_cache
Definition darktable.h:542
struct dt_control_signal_t * signals
Definition darktable.h:540
struct dt_opencl_t * opencl
Definition darktable.h:551
int32_t unmuted
Definition darktable.h:526
struct dt_develop_t * develop
Definition darktable.h:536
char * main_message
Definition darktable.h:604
Definition develop.h:139
size_t height
Definition develop.h:142
uint64_t hash
Definition develop.h:143
size_t width
Definition develop.h:141
void * buffer
Definition develop.h:140
size_t bpp
Definition develop.h:145
Definition colorpicker.h:42
dt_lib_colorpicker_size_t size
Definition colorpicker.h:49
dt_boundingbox_t box
Definition colorpicker.h:48
float point[2]
Definition colorpicker.h:47
Definition pixelpipe.h:48
const struct dt_histogram_roi_t * roi
Definition pixelpipe.h:50
uint32_t bins_count
Definition pixelpipe.h:61
Definition dev_history.h:30
uint64_t hash
Definition dev_history.h:42
dt_iop_params_t * params
Definition dev_history.h:33
char multi_name[128]
Definition dev_history.h:38
struct dt_develop_blend_params_t * blend_params
Definition dev_history.h:34
struct dt_iop_module_t *gboolean enabled
Definition dev_history.h:31
Definition pixelpipe_hb.h:46
gboolean enabled
Definition pixelpipe_hb.h:62
uint32_t histogram_max[4]
Definition pixelpipe_hb.h:68
dt_dev_request_flags_t request_histogram
Definition pixelpipe_hb.h:64
uint64_t blendop_hash
Definition pixelpipe_hb.h:74
struct dt_iop_module_t *struct dt_dev_pixelpipe_t * pipe
Definition pixelpipe_hb.h:48
uint64_t global_hash
Definition pixelpipe_hb.h:78
uint64_t hash
Definition pixelpipe_hb.h:73
dt_iop_buffer_dsc_t dsc_in
Definition pixelpipe_hb.h:93
uint32_t * histogram
Definition pixelpipe_hb.h:66
dt_dev_histogram_stats_t histogram_stats
Definition pixelpipe_hb.h:67
uint64_t global_mask_hash
Definition pixelpipe_hb.h:81
dt_iop_roi_t planned_roi_out
Definition pixelpipe_hb.h:88
gboolean bypass_cache
Definition pixelpipe_hb.h:96
int process_tiling_ready
Definition pixelpipe_hb.h:90
GHashTable * raster_masks
Definition pixelpipe_hb.h:98
dt_dev_histogram_collection_params_t histogram_params
Definition pixelpipe_hb.h:65
void * data
Definition pixelpipe_hb.h:49
void * blendop_data
Definition pixelpipe_hb.h:61
dt_iop_roi_t planned_roi_in
Definition pixelpipe_hb.h:88
Definition pixelpipe_hb.h:126
dt_colorspaces_color_profile_type_t icc_type
Definition pixelpipe_hb.h:197
struct dt_iop_order_iccprofile_info_t * work_profile_info
Definition pixelpipe_hb.h:144
struct dt_iop_order_iccprofile_info_t * input_profile_info
Definition pixelpipe_hb.h:146
int iwidth
Definition pixelpipe_hb.h:132
int want_detail_mask
Definition pixelpipe_hb.h:168
GList * iop
Definition pixelpipe_hb.h:201
int opencl_error
Definition pixelpipe_hb.h:180
struct dt_iop_order_iccprofile_info_t * output_profile_info
Definition pixelpipe_hb.h:148
int running
Definition pixelpipe_hb.h:174
uint64_t backbuf_hash
Definition pixelpipe_hb.h:158
gchar * icc_filename
Definition pixelpipe_hb.h:198
int processed_width
Definition pixelpipe_hb.h:135
dt_dev_pixelpipe_change_t changed
Definition pixelpipe_hb.h:153
uint64_t last_history_hash
Definition pixelpipe_hb.h:212
dt_pthread_mutex_t busy_mutex
Definition pixelpipe_hb.h:159
gboolean flush_cache
Definition pixelpipe_hb.h:230
int mask_display
Definition pixelpipe_hb.h:184
GList * nodes
Definition pixelpipe_hb.h:151
dt_dev_pixelpipe_status_t status
Definition pixelpipe_hb.h:141
dt_imageio_levels_t levels
Definition pixelpipe_hb.h:191
gboolean reentry
Definition pixelpipe_hb.h:218
dt_mipmap_size_t size
Definition pixelpipe_hb.h:129
dt_iop_color_intent_t icc_intent
Definition pixelpipe_hb.h:199
dt_image_t image
Definition pixelpipe_hb.h:195
float * rawdetail_mask_data
Definition pixelpipe_hb.h:166
dt_atomic_int shutdown
Definition pixelpipe_hb.h:176
int output_backbuf_width
Definition pixelpipe_hb.h:162
dt_iop_buffer_dsc_t dsc
Definition pixelpipe_hb.h:139
uint64_t reentry_hash
Definition pixelpipe_hb.h:224
int opencl_enabled
Definition pixelpipe_hb.h:178
int output_backbuf_height
Definition pixelpipe_hb.h:162
uint8_t * output_backbuf
Definition pixelpipe_hb.h:161
dt_dev_pixelpipe_type_t type
Definition pixelpipe_hb.h:189
int processed_height
Definition pixelpipe_hb.h:135
int32_t imgid
Definition pixelpipe_hb.h:128
size_t backbuf_width
Definition pixelpipe_hb.h:156
gboolean store_all_raster_masks
Definition pixelpipe_hb.h:207
dt_pthread_mutex_t backbuf_mutex
Definition pixelpipe_hb.h:159
int bypass_blendif
Definition pixelpipe_hb.h:186
int tiling
Definition pixelpipe_hb.h:182
int iheight
Definition pixelpipe_hb.h:132
struct dt_iop_roi_t rawdetail_mask_roi
Definition pixelpipe_hb.h:167
GList * forms
Definition pixelpipe_hb.h:205
void * backbuf
Definition pixelpipe_hb.h:155
int devid
Definition pixelpipe_hb.h:193
int processing
Definition pixelpipe_hb.h:172
int output_imgid
Definition pixelpipe_hb.h:170
GList * iop_order_list
Definition pixelpipe_hb.h:203
int timeout
Definition pixelpipe_hb.h:235
size_t backbuf_height
Definition pixelpipe_hb.h:156
int input_timestamp
Definition pixelpipe_hb.h:188
Definition blend.h:180
uint32_t mask_mode
Definition blend.h:183
float details
Definition blend.h:209
Definition develop.h:150
int32_t gui_attached
Definition develop.h:153
GList * iop_order_list
Definition develop.h:210
dt_image_t image_storage
Definition develop.h:195
dt_backbuf_t display_histogram
Definition develop.h:232
GList * iop
Definition develop.h:204
dt_backbuf_t output_histogram
Definition develop.h:231
int completed
Definition develop.h:346
struct dt_iop_module_t * gui_module
Definition develop.h:158
dt_pthread_rwlock_t history_mutex
Definition develop.h:198
struct dt_develop_t::@24 progress
struct dt_dev_pixelpipe_t * preview_pipe
Definition develop.h:187
GList * history
Definition develop.h:200
dt_backbuf_t raw_histogram
Definition develop.h:230
int total
Definition develop.h:346
GList * forms
Definition develop.h:220
gboolean loading_cache
Definition develop.h:354
Definition tiling.h:30
float factor
Definition tiling.h:32
unsigned overhead
Definition tiling.h:40
float maxbuf
Definition tiling.h:36
Definition histogram.h:35
int width
Definition histogram.h:36
Definition common/image.h:195
dt_iop_buffer_dsc_t buf_dsc
Definition common/image.h:234
char filename[DT_MAX_FILENAME_LEN]
Definition common/image.h:218
Definition develop/format.h:36
int cst
Definition develop/format.h:62
unsigned int channels
Definition develop/format.h:38
dt_iop_buffer_type_t datatype
Definition develop/format.h:40
dt_aligned_pixel_t processed_maximum
Definition develop/format.h:59
Definition imageop.h:181
dt_dev_request_colorpick_flags_t request_color_pick
Definition imageop.h:199
dt_aligned_pixel_t picked_output_color_min
Definition imageop.h:211
GtkWidget * widget
Definition imageop.h:267
char multi_name[128]
Definition imageop.h:293
struct dt_develop_t * dev
Definition imageop.h:226
GModule *dt_dev_operation_t op
Definition imageop.h:191
dt_dev_request_flags_t request_histogram
Definition imageop.h:201
int iop_order
Definition imageop.h:195
dt_aligned_pixel_t picked_output_color_max
Definition imageop.h:211
uint32_t histogram_max[4]
Definition imageop.h:217
dt_aligned_pixel_t picked_output_color
Definition imageop.h:211
gboolean enabled
Definition imageop.h:228
dt_aligned_pixel_t picked_color_min
Definition imageop.h:209
dt_aligned_pixel_t picked_color_max
Definition imageop.h:209
uint32_t * histogram
Definition imageop.h:213
dt_aligned_pixel_t picked_color
Definition imageop.h:209
Definition iop_profile.h:41
Definition imageop.h:32
int x
Definition imageop.h:33
double scale
Definition imageop.h:34
int width
Definition imageop.h:33
int height
Definition imageop.h:33
int y
Definition imageop.h:33
struct dt_iop_color_picker_t * picker_proxy
Definition libs/lib.h:54
struct dt_lib_t::@52::@53 colorpicker
struct dt_lib_module_t *struct dt_colorpicker_sample_t * primary_sample
Definition libs/lib.h:53
struct dt_lib_t::@52 proxy
Definition mipmap_cache.h:58
int32_t height
Definition mipmap_cache.h:61
uint8_t * buf
Definition mipmap_cache.h:63
int32_t width
Definition mipmap_cache.h:61
int error_count
Definition opencl.h:498
int stopped
Definition opencl.h:497
Definition pixelpipe_cache.c:31
Definition darktable.h:608
#define dt_alloc_align(B)
Definition tests/cache.c:22
#define MIN(a, b)
Definition thinplate.c:23
#define MAX(a, b)
Definition thinplate.c:20
int dt_tiling_piece_fits_host_memory(const size_t width, const size_t height, const unsigned bpp, const float factor, const size_t overhead)
Definition tiling.c:2045