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 is part of darktable,
3 Copyright (C) 2009-2016 johannes hanika.
4 Copyright (C) 2010-2012 Henrik Andersson.
5 Copyright (C) 2011 Bruce Guenter.
6 Copyright (C) 2011 Robert Bieber.
7 Copyright (C) 2011 Rostyslav Pidgornyi.
8 Copyright (C) 2011-2017, 2019 Ulrich Pegelow.
9 Copyright (C) 2012, 2021 Aldric Renaudin.
10 Copyright (C) 2012 Richard Wonka.
11 Copyright (C) 2012-2019 Tobias Ellinghaus.
12 Copyright (C) 2013-2016 Roman Lebedev.
13 Copyright (C) 2013 Simon Spannagel.
14 Copyright (C) 2014, 2016 Pedro Côrte-Real.
15 Copyright (C) 2016 Matthieu Moy.
16 Copyright (C) 2017, 2019 luzpaz.
17 Copyright (C) 2018, 2020-2026 Aurélien PIERRE.
18 Copyright (C) 2018-2019 Edgardo Hoszowski.
19 Copyright (C) 2018-2022 Pascal Obry.
20 Copyright (C) 2019 Andreas Schneider.
21 Copyright (C) 2019-2022 Dan Torop.
22 Copyright (C) 2019-2022 Hanno Schwalm.
23 Copyright (C) 2019 Heiko Bauke.
24 Copyright (C) 2020 Chris Elston.
25 Copyright (C) 2020 Diederik Ter Rahe.
26 Copyright (C) 2020 GrahamByrnes.
27 Copyright (C) 2020-2021 Harold le Clément de Saint-Marcq.
28 Copyright (C) 2020-2021 Hubert Kowalski.
29 Copyright (C) 2020-2021 Ralf Brown.
30 Copyright (C) 2021 Sakari Kapanen.
31 Copyright (C) 2022 Martin Bařinka.
32 Copyright (C) 2022 Philipp Lutz.
33 Copyright (C) 2023-2024 Alynx Zhou.
34 Copyright (C) 2023 lologor.
35 Copyright (C) 2023 Luca Zulberti.
36 Copyright (C) 2024 Alban Gruin.
37 Copyright (C) 2024 tatu.
38 Copyright (C) 2025-2026 Guillaume Stutin.
39 Copyright (C) 2025 Miguel Moquillon.
40
41 darktable is free software: you can redistribute it and/or modify
42 it under the terms of the GNU General Public License as published by
43 the Free Software Foundation, either version 3 of the License, or
44 (at your option) any later version.
45
46 darktable is distributed in the hope that it will be useful,
47 but WITHOUT ANY WARRANTY; without even the implied warranty of
48 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
49 GNU General Public License for more details.
50
51 You should have received a copy of the GNU General Public License
52 along with darktable. If not, see <http://www.gnu.org/licenses/>.
53*/
54#include "common/colorspaces.h"
55#include "common/darktable.h"
56#include "common/histogram.h"
57#include "common/imageio.h"
58#include "common/atomic.h"
59#include "common/opencl.h"
60#include "common/iop_order.h"
61#include "control/control.h"
62#include "control/conf.h"
63#include "control/signal.h"
64#include "develop/blend.h"
66#include "develop/format.h"
68#include "develop/pixelpipe.h"
74#include "develop/tiling.h"
75#include "develop/masks.h"
76#include "gui/gtk.h"
77#include "libs/colorpicker.h"
78#include "libs/lib.h"
80
81#include <assert.h>
82#include <inttypes.h>
83#include <math.h>
84#include <stdint.h>
85#include <stdlib.h>
86#include <string.h>
87#include <strings.h>
88#include <unistd.h>
89
93
94static void _trace_cache_owner(const dt_dev_pixelpipe_t *pipe, const dt_iop_module_t *module,
95 const char *phase, const char *slot, const uint64_t requested_hash,
96 const void *buffer, const dt_pixel_cache_entry_t *entry,
97 const gboolean verbose)
98{
99 if(!(darktable.unmuted & DT_DEBUG_CACHE)) return;
100 if(verbose && !(darktable.unmuted & DT_DEBUG_VERBOSE)) return;
101
103 "[pixelpipe_owner] pipe=%s module=%s phase=%s slot=%s req=%" PRIu64
104 " entry=%" PRIu64 "/%" PRIu64 " refs=%i auto=%i data=%p buf=%p name=%s\n",
105 pipe ? dt_pixelpipe_get_pipe_name(pipe->type) : "-",
106 module ? module->op : "base",
107 phase ? phase : "-",
108 slot ? slot : "-",
109 requested_hash,
110 entry ? entry->hash : DT_PIXELPIPE_CACHE_HASH_INVALID,
111 entry ? entry->serial : 0,
112 entry ? dt_atomic_get_int((dt_atomic_int *)&entry->refcount) : -1,
113 entry ? entry->auto_destroy : -1,
114 entry ? entry->data : NULL,
115 buffer,
116 (entry && entry->name) ? entry->name : "-");
117}
118
119
120static void _trace_buffer_content(const dt_dev_pixelpipe_t *pipe, const dt_iop_module_t *module,
121 const char *phase, const void *buffer,
122 const dt_iop_buffer_dsc_t *format, const dt_iop_roi_t *roi)
123{
124 if(!(darktable.unmuted & DT_DEBUG_CACHE)) return;
125 if(!(darktable.unmuted & DT_DEBUG_VERBOSE)) return;
126 if(!buffer || !format || !roi) return;
127 if(roi->width <= 0 || roi->height <= 0) return;
128
129 const size_t pixels = (size_t)roi->width * (size_t)roi->height;
130 const unsigned int channels = format->channels;
131
132 if(format->datatype == TYPE_FLOAT && channels >= 1)
133 {
134 const float *in = (const float *)buffer;
135 float minv[4] = { FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX };
136 float maxv[4] = { -FLT_MAX, -FLT_MAX, -FLT_MAX, -FLT_MAX };
137 size_t nonfinite = 0;
138 size_t near_black = 0;
139
140 for(size_t k = 0; k < pixels; k++, in += channels)
141 {
142 gboolean finite = TRUE;
143 for(unsigned int c = 0; c < MIN(channels, 4U); c++)
144 {
145 if(!isfinite(in[c]))
146 {
147 finite = FALSE;
148 continue;
149 }
150 minv[c] = fminf(minv[c], in[c]);
151 maxv[c] = fmaxf(maxv[c], in[c]);
152 }
153
154 if(!finite)
155 {
156 nonfinite++;
157 continue;
158 }
159
160 const float energy = fabsf(in[0]) + ((channels > 1) ? fabsf(in[1]) : 0.0f)
161 + ((channels > 2) ? fabsf(in[2]) : 0.0f);
162 if(energy < 1e-6f) near_black++;
163 }
164
166 "[pixelpipe_stats] pipe=%s module=%s phase=%s type=float ch=%u roi=%dx%d "
167 "rgb_min=(%g,%g,%g) rgb_max=(%g,%g,%g) a_min=%g a_max=%g near_black=%zu/%zu nonfinite=%zu\n",
168 dt_pixelpipe_get_pipe_name(pipe->type), module->op, phase ? phase : "-",
169 channels, roi->width, roi->height,
170 minv[0], (channels > 1) ? minv[1] : 0.0f, (channels > 2) ? minv[2] : 0.0f,
171 maxv[0], (channels > 1) ? maxv[1] : 0.0f, (channels > 2) ? maxv[2] : 0.0f,
172 (channels > 3) ? minv[3] : 0.0f, (channels > 3) ? maxv[3] : 0.0f,
173 near_black, pixels, nonfinite);
174 }
175 else if(format->datatype == TYPE_UINT8 && channels >= 1)
176 {
177 const uint8_t *in = (const uint8_t *)buffer;
178 int minv[4] = { 255, 255, 255, 255 };
179 int maxv[4] = { 0, 0, 0, 0 };
180 size_t near_black = 0;
181
182 for(size_t k = 0; k < pixels; k++, in += channels)
183 {
184 for(unsigned int c = 0; c < MIN(channels, 4U); c++)
185 {
186 minv[c] = MIN(minv[c], in[c]);
187 maxv[c] = MAX(maxv[c], in[c]);
188 }
189
190 const int energy = in[0] + ((channels > 1) ? in[1] : 0) + ((channels > 2) ? in[2] : 0);
191 if(energy == 0) near_black++;
192 }
193
195 "[pixelpipe_stats] pipe=%s module=%s phase=%s type=u8 ch=%u roi=%dx%d "
196 "rgb_min=(%d,%d,%d) rgb_max=(%d,%d,%d) a_min=%d a_max=%d near_black=%zu/%zu\n",
197 dt_pixelpipe_get_pipe_name(pipe->type), module->op, phase ? phase : "-",
198 channels, roi->width, roi->height,
199 minv[0], (channels > 1) ? minv[1] : 0, (channels > 2) ? minv[2] : 0,
200 maxv[0], (channels > 1) ? maxv[1] : 0, (channels > 2) ? maxv[2] : 0,
201 (channels > 3) ? minv[3] : 0, (channels > 3) ? maxv[3] : 0,
202 near_black, pixels);
203 }
204}
205
207 dt_iop_module_t *module, const uint64_t input_hash,
208 const void *input, dt_pixel_cache_entry_t *input_entry,
209 const uint64_t output_hash, void **output,
210 void **cl_mem_output, dt_pixel_cache_entry_t *output_entry)
211{
212 _trace_cache_owner(pipe, module, "shutdown-drop", "input", input_hash, input, input_entry, FALSE);
213 _trace_cache_owner(pipe, module, "shutdown-drop", "output", output_hash,
214 output ? *output : NULL, output_entry, FALSE);
215
217
218 if(input_entry)
219 {
222 }
223
224 if(output_entry)
225 {
227
230 }
231
232 if(output) *output = NULL;
233
234 if(*cl_mem_output != NULL)
235 dt_dev_pixelpipe_gpu_clear_buffer(cl_mem_output, NULL, NULL, FALSE);
236
237 dt_iop_nap(5000);
239 return 1;
240}
241
242static inline gboolean _is_focused_realtime_gui_module(const dt_dev_pixelpipe_t *pipe,
243 const dt_develop_t *dev,
244 const dt_iop_module_t *module)
245{
246 return pipe && (pipe->type == DT_DEV_PIXELPIPE_FULL || pipe->type == DT_DEV_PIXELPIPE_PREVIEW)
247 && pipe->realtime && dev && module && dev->gui_module == module;
248}
249
250
252 const dt_pixel_cache_entry_t *cache_entry)
253{
254 return pipe && (pipe->realtime
255 || (cache_entry
256 && dt_pixel_cache_entry_get_data((dt_pixel_cache_entry_t *)cache_entry) == NULL));
257}
258
260{
261 char *r = NULL;
262
263 switch(pipe_type)
264 {
266 r = _("preview");
267 break;
269 r = _("full");
270 break;
272 r = _("thumbnail");
273 break;
275 r = _("export");
276 break;
277 default:
278 r = _("invalid");
279 }
280 return r;
281}
282
283inline static void _copy_buffer(const char *const restrict input, char *const restrict output,
284 const size_t height, const size_t o_width, const size_t i_width,
285 const size_t x_offset, const size_t y_offset,
286 const size_t stride, const size_t bpp)
287{
288#ifdef _OPENMP
289#pragma omp parallel for default(none) \
290 dt_omp_firstprivate(input, output, bpp, o_width, i_width, height, x_offset, y_offset, stride) \
291 schedule(static)
292#endif
293 for(size_t j = 0; j < height; j++)
294 // Since we crop 1-channel RAW arbitrarily here, alignment is never guaranteed
295 memcpy(output + bpp * j * o_width,
296 input + bpp * (x_offset + (y_offset + j) * i_width),
297 stride);
298}
299
300
301inline static void _uint8_to_float(const uint8_t *const input, float *const output,
302 const size_t width, const size_t height, const size_t chan)
303{
304#ifdef _OPENMP
305#pragma omp parallel for simd default(none) \
306 aligned(input, output: 64) \
307 dt_omp_firstprivate(input, output, width, height, chan) \
308 schedule(static)
309#endif
310 for(size_t k = 0; k < height * width; k++)
311 {
312 const size_t index = k * chan;
313 // Warning: we take BGRa and put it back into RGBa
314 output[index + 0] = (float)input[index + 2] / 255.f;
315 output[index + 1] = (float)input[index + 1] / 255.f;
316 output[index + 2] = (float)input[index + 0] / 255.f;
317 output[index + 3] = 0.f;
318 }
319}
320
321static const char *_debug_cst_to_string(const int cst)
322{
323 switch(cst)
324 {
325 case IOP_CS_RAW:
326 return "raw";
327 case IOP_CS_LAB:
328 return "lab";
329 case IOP_CS_RGB:
330 return "rgb";
331 case IOP_CS_LCH:
332 return "lch";
333 case IOP_CS_HSL:
334 return "hsl";
335 case IOP_CS_JZCZHZ:
336 return "jzczhz";
337 case IOP_CS_NONE:
338 return "none";
339 default:
340 return "unknown";
341 }
342}
343
345{
346 switch(type)
347 {
348 case TYPE_FLOAT:
349 return "float";
350 case TYPE_UINT16:
351 return "uint16";
352 case TYPE_UINT8:
353 return "uint8";
354 case TYPE_UNKNOWN:
355 default:
356 return "unknown";
357 }
358}
359
361 const gboolean is_cl,
362 const dt_iop_buffer_dsc_t *in_dsc, const dt_iop_buffer_dsc_t *out_dsc,
363 const dt_iop_roi_t *roi_in, const dt_iop_roi_t *roi_out,
364 const size_t in_bpp, const size_t out_bpp,
365 const int cst_before, const int cst_after)
366{
367 if(!(darktable.unmuted & DT_DEBUG_PIPE)) return;
368 if(!(darktable.unmuted & DT_DEBUG_VERBOSE)) return;
369 const char *module_name = module ? module->op : "base";
370 const char *pipe_name = dt_pixelpipe_get_pipe_name(pipe->type);
371 const char *stage_name = stage ? stage : "process";
372
373 if(in_dsc && out_dsc)
374 {
376 "[pixelpipe] %s %s %s %s: in cst=%s->%s ch=%d type=%s bpp=%zu roi=%dx%d | "
377 "out cst=%s ch=%d type=%s bpp=%zu roi=%dx%d\n",
378 pipe_name, module_name, is_cl ? "cl" : "cpu", stage_name,
379 _debug_cst_to_string(cst_before), _debug_cst_to_string(cst_after),
380 in_dsc->channels, _debug_type_to_string(in_dsc->datatype), in_bpp,
381 roi_in ? roi_in->width : 0, roi_in ? roi_in->height : 0,
382 _debug_cst_to_string(out_dsc->cst), out_dsc->channels, _debug_type_to_string(out_dsc->datatype),
383 out_bpp, roi_out ? roi_out->width : 0, roi_out ? roi_out->height : 0);
384 }
385 else if(out_dsc)
386 {
388 "[pixelpipe] %s %s %s %s: out cst=%s ch=%d type=%s bpp=%zu roi=%dx%d\n",
389 pipe_name, module_name, is_cl ? "cl" : "cpu", stage_name,
390 _debug_cst_to_string(out_dsc->cst), out_dsc->channels, _debug_type_to_string(out_dsc->datatype),
391 out_bpp, roi_out ? roi_out->width : 0, roi_out ? roi_out->height : 0);
392 }
393}
394
395
396int dt_dev_pixelpipe_init_export(dt_dev_pixelpipe_t *pipe, int levels, gboolean store_masks)
397{
398 const int res = dt_dev_pixelpipe_init_cached(pipe);
401 pipe->levels = levels;
402 pipe->store_all_raster_masks = store_masks;
403 return res;
404}
405
407{
408 const int res = dt_dev_pixelpipe_init_cached(pipe);
410 pipe->no_cache = TRUE;
411 return res;
412}
413
415{
416 const int res = dt_dev_pixelpipe_init_cached(pipe);
418 pipe->no_cache = TRUE;
419 return res;
420}
421
423{
424 // Init with the size of MIPMAP_F
425 const int res = dt_dev_pixelpipe_init_cached(pipe);
428
429 // Needed for caching
431 return res;
432}
433
435{
436 const int res = dt_dev_pixelpipe_init_cached(pipe);
438
439 // Needed for caching
441 return res;
442}
443
445{
446 // Set everything to 0 = NULL = FALSE
447 memset(pipe, 0, sizeof(dt_dev_pixelpipe_t));
448
449 // Set only the stuff that doesn't take 0 as default
450 pipe->devid = -1;
454 dt_dev_set_backbuf(&pipe->backbuf, 0, 0, 0, -1, -1);
456
460
462 dt_pthread_mutex_init(&(pipe->busy_mutex), NULL);
463
466
468 return 1;
469}
470
472{
473 if(!pipe) return;
474 dt_atomic_set_int(&pipe->realtime, state ? TRUE : FALSE);
475}
476
478{
479 return pipe ? dt_atomic_get_int((dt_atomic_int *)&pipe->realtime) : FALSE;
480}
481
484{
485 pipe->iwidth = width;
486 pipe->iheight = height;
487 pipe->imgid = imgid;
488 pipe->image = dev->image_storage;
489 pipe->size = size;
490}
491
493 const gchar *icc_filename, dt_iop_color_intent_t icc_intent)
494{
495 pipe->icc_type = icc_type;
496 dt_free(pipe->icc_filename);
497 pipe->icc_filename = g_strdup(icc_filename ? icc_filename : "");
498 pipe->icc_intent = icc_intent;
499}
500
502{
503 /* Device-side cache payloads are only an acceleration layer. Once darkroom
504 * leaves and all pipe workers are quiescent, drop all cached cl_mem objects
505 * so a later reopen can only exact-hit host-authoritative cachelines. */
507
508 // blocks while busy and sets shutdown bit:
510 // so now it's safe to clean up cache:
511 const uint64_t old_backbuf_hash = dt_dev_backbuf_get_hash(&pipe->backbuf);
512 if(pipe->no_cache)
513 {
514 dt_pixel_cache_entry_t *old_backbuf_entry
518 }
521 dt_free(pipe->icc_filename);
522
524
526
527 if(pipe->forms)
528 {
529 g_list_free_full(pipe->forms, (void (*)(void *))dt_masks_free_form);
530 pipe->forms = NULL;
531 }
532}
533
534
536{
538 {
539 pipe->reentry = TRUE;
540 pipe->reentry_hash = hash;
541 dt_print(DT_DEBUG_DEV, "[dev_pixelpipe] re-entry flag set for %" PRIu64 "\n", hash);
542 return TRUE;
543 }
544
545 return FALSE;
546}
547
548
550{
551 if(pipe->reentry_hash == hash)
552 {
553 pipe->reentry = FALSE;
555 dt_print(DT_DEBUG_DEV, "[dev_pixelpipe] re-entry flag unset for %" PRIu64 "\n", hash);
556 return TRUE;
557 }
558
559 return FALSE;
560}
561
563{
564 return pipe->reentry;
565}
566
573
575{
576 // destroy all nodes
577 for(GList *nodes = g_list_first(pipe->nodes); nodes; nodes = g_list_next(nodes))
578 {
580 if(piece == NULL) continue;
581 // printf("cleanup module `%s'\n", piece->module->name());
582 if(piece->module) dt_iop_cleanup_pipe(piece->module, pipe, piece);
584 dt_free(piece);
585 }
586 g_list_free(pipe->nodes);
587 pipe->nodes = NULL;
588 // and iop order
589 g_list_free_full(pipe->iop_order_list, dt_free_gpointer);
590 pipe->iop_order_list = NULL;
591}
592
594{
595 // check that the pipe was actually properly cleaned up after the last run
596 g_assert(pipe->nodes == NULL);
597 g_assert(pipe->iop_order_list == NULL);
599
600 // for all modules in dev:
601 for(GList *modules = g_list_first(dev->iop); modules; modules = g_list_next(modules))
602 {
603 dt_iop_module_t *module = (dt_iop_module_t *)modules->data;
605 if(!piece) continue;
606 piece->enabled = module->enabled;
607 piece->request_histogram = DT_REQUEST_ONLY_IN_GUI;
608 piece->histogram_params.bins_count = 256;
609 piece->iwidth = pipe->iwidth;
610 piece->iheight = pipe->iheight;
611 piece->module = module;
613 piece->blendop_hash = DT_PIXELPIPE_CACHE_HASH_INVALID;
614 piece->global_hash = DT_PIXELPIPE_CACHE_HASH_INVALID;
615 piece->global_mask_hash = DT_PIXELPIPE_CACHE_HASH_INVALID;
617 piece->force_opencl_cache = TRUE;
618 piece->raster_masks = dt_pixelpipe_raster_alloc();
619
620 // dsc_mask is static, single channel float image
621 piece->dsc_mask.channels = 1;
622 piece->dsc_mask.datatype = TYPE_FLOAT;
623 dt_iop_buffer_dsc_update_bpp(&piece->dsc_mask);
624
625 dt_iop_init_pipe(piece->module, pipe, piece);
626
627 pipe->nodes = g_list_append(pipe->nodes, piece);
628 }
629}
630
632 const dt_dev_pixelpipe_iop_t *const piece,
633 const dt_iop_buffer_dsc_t *const output_dsc)
634{
639
640 const dt_iop_colorspace_type_t blend_cst = dt_develop_blend_colorspace(piece, output_dsc->cst);
642 if(piece->dsc_in.cst != blend_cst)
644 if(output_dsc->cst != blend_cst)
646
647 return transforms;
648}
649
650#define KILL_SWITCH_ABORT \
651 if(dt_atomic_get_int(&pipe->shutdown)) \
652 { \
653 if(cl_mem_output != NULL) \
654 { \
655 dt_dev_pixelpipe_gpu_clear_buffer(&cl_mem_output, NULL, NULL, FALSE); \
656 } \
657 dt_iop_nap(5000); \
658 pipe->status = DT_DEV_PIXELPIPE_DIRTY; \
659 return 1; \
660 }
661
662// Once we have a cache, stopping computation before full completion
663// has good chances of leaving it corrupted. So we invalidate it.
664#define KILL_SWITCH_AND_FLUSH_CACHE \
665 if(dt_atomic_get_int(&pipe->shutdown)) \
666 { \
667 return _abort_module_shutdown_cleanup(pipe, piece, module, input_hash, input, input_entry, hash, &output, \
668 &cl_mem_output, output_entry); \
669 }
670
671static void _print_perf_debug(dt_dev_pixelpipe_t *pipe, const dt_pixelpipe_flow_t pixelpipe_flow,
673 const gboolean recycled_output_cacheline, dt_times_t *start)
674{
675 char histogram_log[32] = "";
676 if(!(pixelpipe_flow & PIXELPIPE_FLOW_HISTOGRAM_NONE))
677 {
678 snprintf(histogram_log, sizeof(histogram_log), ", collected histogram on %s",
679 (pixelpipe_flow & PIXELPIPE_FLOW_HISTOGRAM_ON_GPU
680 ? "GPU"
681 : pixelpipe_flow & PIXELPIPE_FLOW_HISTOGRAM_ON_CPU ? "CPU" : ""));
682 }
683
684 gchar *module_label = dt_history_item_get_name(module);
686 start, "[dev_pixelpipe]", "processed `%s' on %s%s%s%s, blended on %s [%s]", module_label,
687 pixelpipe_flow & PIXELPIPE_FLOW_PROCESSED_ON_GPU
688 ? "GPU"
689 : pixelpipe_flow & PIXELPIPE_FLOW_PROCESSED_ON_CPU ? "CPU" : "",
690 pixelpipe_flow & PIXELPIPE_FLOW_PROCESSED_WITH_TILING ? " with tiling" : "",
691 recycled_output_cacheline ? ", recycled cacheline" : "",
692 (!(pixelpipe_flow & PIXELPIPE_FLOW_HISTOGRAM_NONE) && (piece->request_histogram & DT_REQUEST_ON))
693 ? histogram_log
694 : "",
695 pixelpipe_flow & PIXELPIPE_FLOW_BLENDED_ON_GPU
696 ? "GPU"
697 : pixelpipe_flow & PIXELPIPE_FLOW_BLENDED_ON_CPU ? "CPU" : "",
699 dt_free(module_label);
700}
701
702
703static void _print_nan_debug(dt_dev_pixelpipe_t *pipe, void *cl_mem_output, void *output,
704 const dt_iop_roi_t *roi_out, dt_iop_buffer_dsc_t *out_format,
705 dt_iop_module_t *module)
706{
707 if(!(darktable.unmuted & DT_DEBUG_NAN)) return;
708 if(!(darktable.unmuted & DT_DEBUG_VERBOSE)) return;
709 if((darktable.unmuted & DT_DEBUG_NAN) && strcmp(module->op, "gamma") != 0)
710 {
711 gchar *module_label = dt_history_item_get_name(module);
712
713 if(out_format->datatype == TYPE_FLOAT && out_format->channels == 4)
714 {
715 int hasinf = 0, hasnan = 0;
716 dt_aligned_pixel_t min = { FLT_MAX };
717 dt_aligned_pixel_t max = { FLT_MIN };
718
719 for(int k = 0; k < 4 * roi_out->width * roi_out->height; k++)
720 {
721 if((k & 3) < 3)
722 {
723 float f = ((float *)(output))[k];
724 if(isnan(f))
725 hasnan = 1;
726 else if(isinf(f))
727 hasinf = 1;
728 else
729 {
730 min[k & 3] = fmin(f, min[k & 3]);
731 max[k & 3] = fmax(f, max[k & 3]);
732 }
733 }
734 }
735 if(hasnan)
736 fprintf(stderr, "[dev_pixelpipe] module `%s' outputs NaNs! [%s]\n", module_label,
738 if(hasinf)
739 fprintf(stderr, "[dev_pixelpipe] module `%s' outputs non-finite floats! [%s]\n", module_label,
741 fprintf(stderr, "[dev_pixelpipe] module `%s' min: (%f; %f; %f) max: (%f; %f; %f) [%s]\n", module_label,
742 min[0], min[1], min[2], max[0], max[1], max[2], dt_pixelpipe_get_pipe_name(pipe->type));
743 }
744 else if(out_format->datatype == TYPE_FLOAT && out_format->channels == 1)
745 {
746 int hasinf = 0, hasnan = 0;
747 float min = FLT_MAX;
748 float max = FLT_MIN;
749
750 for(int k = 0; k < roi_out->width * roi_out->height; k++)
751 {
752 float f = ((float *)(output))[k];
753 if(isnan(f))
754 hasnan = 1;
755 else if(isinf(f))
756 hasinf = 1;
757 else
758 {
759 min = fmin(f, min);
760 max = fmax(f, max);
761 }
762 }
763 if(hasnan)
764 fprintf(stderr, "[dev_pixelpipe] module `%s' outputs NaNs! [%s]\n", module_label,
766 if(hasinf)
767 fprintf(stderr, "[dev_pixelpipe] module `%s' outputs non-finite floats! [%s]\n", module_label,
769 fprintf(stderr, "[dev_pixelpipe] module `%s' min: (%f) max: (%f) [%s]\n", module_label, min, max,
771 }
772
773 dt_free(module_label);
774 }
775}
776
778{
779 for(GList *node = g_list_first(pipe->nodes); node; node = g_list_next(node))
780 {
782 if(piece && piece->enabled)
783 return &piece->roi_in;
784 }
785
786 return NULL;
787}
788
789// return 1 on error
791{
792 /* `dev` is only needed for darkroom pipes to expose the long base-buffer load in the GUI.
793 * Headless callers pass NULL and keep this path side-effect free. */
794 const dt_iop_buffer_dsc_t *out_format = &pipe->image.dsc;
795 const size_t bpp = out_format->bpp;
796 const dt_iop_roi_t roi = *_get_first_roi(pipe);
797 const size_t bufsize = bpp * roi.width * roi.height;
798 const uint64_t hash = dt_dev_pixelpipe_node_hash(pipe, NULL, roi, 0);
799
800 // Note: dt_dev_pixelpipe_cache_get actually init/alloc *output
801 dt_pixel_cache_entry_t *cache_entry;
802 void *output;
803 int new_entry = dt_dev_pixelpipe_cache_get(darktable.pixelpipe_cache, hash, bufsize, "base buffer", pipe->type,
804 TRUE, &output, &cache_entry);
805 if(cache_entry == NULL) return 1;
806
807 int err = 0;
808 gboolean host_rewritten = FALSE;
809
810 if(new_entry)
811 {
812 // Grab input buffer from mipmap cache.
813 // We will have to copy it here and in pixelpipe cache because it can get evicted from mipmap cache
814 // anytime after we release the lock, so it would not be thread-safe to just use a reference
815 // to full-sized buffer. Otherwise, skip dt_dev_pixelpipe_cache_get and
816 // *output = buf.buf for 1:1 at full resolution.
819
820 // Cache size has changed since we inited pipe input ?
821 // Note: we know pipe->iwidth/iheight are non-zero or we would have not launched a pipe.
822 // Note 2: there is no valid reason for a cacheline to change size during runtime.
823 if(!buf.buf || buf.height != pipe->iheight || buf.width != pipe->iwidth || !output)
824 {
825 // Nothing we can do, we need to recompute roi_in and roi_out from scratch
826 // for all modules with new sizes. Exit on error and catch that in develop.
828 err = 1;
829 }
830 else
831 {
832 // 1:1 pixel copies.
833 if(roi.width > 0 && roi.height > 0)
834 {
835 // last minute clamping to catch potential out-of-bounds in roi_in and roi_out
836 // FIXME: this is too late to catch this. Find out why it's needed here and fix upstream.
837 const int in_x = MAX(roi.x, 0);
838 const int in_y = MAX(roi.y, 0);
839 const int cp_width = MIN(roi.width, pipe->iwidth - in_x);
840 const int cp_height = MIN(roi.height, pipe->iheight - in_y);
841
842 _copy_buffer((const char *const)buf.buf, (char *const)output, cp_height, roi.width,
843 pipe->iwidth, in_x, in_y, bpp * cp_width, bpp);
844 host_rewritten = TRUE;
845
846 dt_dev_pixelpipe_debug_dump_module_io(pipe, NULL, "base-init", FALSE, NULL, out_format, NULL, &roi,
848
850 err = 0;
851 }
852 else
853 {
854 // Invalid dimensions
856 err = 1;
857 }
858 }
859 }
860 // else found in cache.
861
862 if(new_entry)
864
865 if(!err && host_rewritten)
866 {
867 dt_dev_pixelpipe_gpu_flush_host_pinned_images(pipe, output, cache_entry, "base buffer copy");
868 /* The base buffer now owns the authoritative host pixels for this cacheline. Any older device-only
869 * payloads attached to the reused cache entry are stale and must not survive into later thumbnail runs,
870 * otherwise a downstream GPU->CPU fallback can reopen previous-image pixels from the same entry. */
871 dt_pixel_cache_clmem_flush(cache_entry);
872 }
873
874 // For one-shot pipelines (thumbnail export), ensure the base buffer cacheline is not kept around.
875 // It will be freed as soon as the next module is done consuming it as input.
876 if(pipe->no_cache)
878
879 if(err)
881
882 return err;
883}
884
886 uint64_t *out_hash, const dt_dev_pixelpipe_iop_t **out_piece,
887 GList *pieces, int pos)
888{
889 // The pipeline is executed recursively, from the end. For each module n, starting from the end,
890 // if output is cached, take it, else if input is cached, take it, process it and output,
891 // else recurse to the previous module n-1 to get a an input.
892 void *input = NULL;
893 void *output = NULL;
894 void *cl_mem_output = NULL;
895
897
898 if(pieces == NULL)
899 {
900 // No pieces means step 0 : init the base buffer
901 dt_times_t start;
902 dt_get_times(&start);
903 if(_init_base_buffer(pipe))
904 return 1;
905
906 dt_show_times_f(&start, "[dev_pixelpipe]", "initing base buffer [%s]", dt_pixelpipe_get_pipe_name(pipe->type));
907 *out_hash = dt_dev_pixelpipe_node_hash(pipe, NULL, *_get_first_roi(pipe), pos);
908 *out_piece = NULL;
909 return 0;
910 }
911
912 dt_iop_module_t *module = NULL;
914
916
917 // skip this module?
918 if(!piece->enabled)
919 return dt_dev_pixelpipe_process_rec(pipe, dev, out_hash, out_piece, g_list_previous(pieces), pos - 1);
920
921 module = piece->module;
922
923 if(dev->gui_attached) dev->progress.total++;
924
926
927 const uint64_t hash = dt_dev_pixelpipe_node_hash(pipe, piece, piece->roi_out, pos);
928
929 // 1) Fast-track:
930 // If we have a cache entry for this hash, return it straight away,
931 // don't recurse through pipeline and don't process, unless this module still
932 // needs GUI-side sampling from its host input or the gamma display histogram
933 // needs the upstream cache entry.
934 dt_pixel_cache_entry_t *existing_cache = NULL;
935 void *existing_output = NULL;
936 const gboolean exact_output_cache_hit
937 = _requests_cache(pipe, piece)
938 && dt_dev_pixelpipe_cache_peek(darktable.pixelpipe_cache, hash, &existing_output, &existing_cache,
939 -1, NULL);
940
941 if(exact_output_cache_hit)
942 {
943 _trace_cache_owner(pipe, module, "exact-hit-direct", "output", hash, NULL, existing_cache, FALSE);
944 *out_hash = hash;
945 *out_piece = piece;
946 return 0;
947 }
948
949 // 3) now recurse through the pipeline.
951 const dt_dev_pixelpipe_iop_t *previous_piece = NULL;
952 if(dt_dev_pixelpipe_process_rec(pipe, dev, &input_hash, &previous_piece, g_list_previous(pieces), pos - 1))
953 {
954 /* Child recursion failed before this module acquired any output cache entry.
955 * Dropping `hash` here underflows cached exact-hit outputs during shutdown. */
957 "[picker/rec] module=%s child recursion failed input_hash=%" PRIu64 " output_hash=%" PRIu64 "\n",
958 module->op, input_hash, hash);
959 return 1;
960 }
961
963
964 // Child recursion just published this hash. Reopen the live cache entry directly instead of going
965 // through exact-hit lookup, because exact-hit intentionally rejects auto-destroy entries while
966 // the parent recursion still needs to consume transient outputs in the same run.
967 dt_pixel_cache_entry_t *input_entry
969 if(!input_entry)
970 {
972 "[picker/rec] module=%s input cache entry missing input_hash=%" PRIu64 " output_hash=%" PRIu64
973 " prev_module=%s prev_hash=%" PRIu64 "\n",
974 module->op, input_hash, hash,
975 previous_piece ? previous_piece->module->op : "base",
976 previous_piece ? previous_piece->global_hash
977 : dt_dev_pixelpipe_node_hash(pipe, NULL, *_get_first_roi(pipe), 0));
978 return 1;
979 }
981 input = dt_pixel_cache_entry_get_data(input_entry);
982 _trace_cache_owner(pipe, module, "acquire", "input", input_hash, input, input_entry, FALSE);
983 _trace_buffer_content(pipe, module, "input-acquire", input, &piece->dsc_in, &piece->roi_in);
984 const size_t bufsize = (size_t)piece->dsc_out.bpp * piece->roi_out.width * piece->roi_out.height;
985 // Note: input == NULL is valid if we are on a GPU-only path, aka previous module ran on GPU
986 // without leaving its output on a RAM cache copy, and current module will also run on GPU.
987 // In this case, we rely on cl_mem_input for best performance (avoid memcpy between RAM and GPU).
988 // Should the GPU path fail at process time, we will init input and flush cl_mem_input into it.
989 // In any case, this avoids carrying a possibly-uninited input buffer, without knowing if it has
990 // data on it (or having to blindly copy back from vRAM to RAM).
991
992 // 3c) actually process this module BUT treat all bypasses first.
993 // special case: user requests to see channel data in the parametric mask of a module, or the blending
994 // mask. In that case we skip all modules manipulating pixel content and only process image distorting
995 // modules. Finally "gamma" is responsible for displaying channel/mask data accordingly.
996 if(dev->gui_attached
998 && !(module->operation_tags() & IOP_TAG_DISTORT)
999 && (piece->dsc_in.bpp == piece->dsc_out.bpp)
1000 && !memcmp(&piece->roi_in, &piece->roi_out, sizeof(struct dt_iop_roi_t)))
1001 {
1002 /* Mask/channel passthrough keeps the exact child buffer alive for the next
1003 * downstream module. This stage does not publish a new cacheline, so it
1004 * must forward the child hash and actual previous piece contract exactly as
1005 * they came from recursion. */
1007 *out_hash = input_hash;
1008 *out_piece = previous_piece;
1009 return 0;
1010 }
1011
1012 if(dev->gui_attached)
1013 {
1014 gchar *module_label = dt_history_item_get_name(module);
1016 darktable.main_message = g_strdup_printf(_("Processing module `%s` for pipeline %s (%ix%i px @ %0.f%%)..."),
1017 module_label, dt_pixelpipe_get_pipe_name(pipe->type),
1018 piece->roi_out.width, piece->roi_out.height, piece->roi_out.scale * 100.f);
1019 dt_free(module_label);
1021 }
1022
1023 dt_pixel_cache_entry_t *output_entry = NULL;
1024 gchar *type = dt_pixelpipe_get_pipe_name(pipe->type);
1025
1027
1028 gchar *name = g_strdup_printf("module %s (%s) for pipe %s", module->op, module->multi_name, type);
1029 gboolean cache_output = piece->force_opencl_cache;
1030 const gboolean allow_cache_reuse = !(darktable.unmuted & DT_DEBUG_NOCACHE_REUSE);
1031 /* `piece->cache_entry` is only valid as a writable-reuse hint for transient outputs that will
1032 * be fully overwritten later. As soon as we keep the current output as a published cacheline in
1033 * RAM, rekey reuse must stop for that piece so later runs cannot overwrite a long-term state in
1034 * place just because the pipe is running in realtime. */
1035 const gboolean allow_rekey_reuse = dev && _requests_cache(pipe, piece) && allow_cache_reuse
1036 && !cache_output;
1037 const dt_dev_pixelpipe_cache_writable_status_t acquire_status
1039 cache_output, allow_rekey_reuse,
1040 allow_rekey_reuse ? &piece->cache_entry : NULL,
1041 &output, &output_entry);
1042 dt_free(name);
1043 if(acquire_status == DT_DEV_PIXELPIPE_CACHE_WRITABLE_EXACT_HIT)
1044 {
1045 /* Another pipe already owns a cacheline for this exact hash. If that cacheline is
1046 * still write-locked, this is not a processing error: it only means the concurrent
1047 * publisher has not finished exposing the exact-hit payload yet. Wait for that
1048 * publication to complete instead of aborting the whole recursion. */
1049 dt_pixel_cache_entry_t *exact_entry
1051 if(!exact_entry)
1052 {
1054 "[picker/rec] module=%s exact-hit entry missing output_hash=%" PRIu64 "\n",
1055 module->op, hash);
1057 return 1;
1058 }
1059
1064
1065 _trace_cache_owner(pipe, module, "exact-hit-wait", "output", hash,
1066 dt_pixel_cache_entry_get_data(exact_entry), exact_entry, FALSE);
1067
1069 *out_hash = hash;
1070 *out_piece = piece;
1071 return 0;
1072 }
1073 if(!output_entry)
1074 {
1076 "[picker/rec] module=%s writable output acquisition failed output_hash=%" PRIu64
1077 " acquire_status=%d\n",
1078 module->op, hash, acquire_status);
1080 return 1;
1081 }
1082 const gboolean new_entry = (acquire_status == DT_DEV_PIXELPIPE_CACHE_WRITABLE_CREATED);
1083 _trace_cache_owner(pipe, module, (acquire_status == DT_DEV_PIXELPIPE_CACHE_WRITABLE_REKEYED) ? "acquire-rekeyed"
1084 : (new_entry ? "acquire-new" : "acquire-existing"),
1085 "output", hash, output, output_entry, FALSE);
1086
1087 /* get tiling requirement of module */
1089 tiling.factor_cl = tiling.maxbuf_cl = -1; // set sentinel value to detect whether callback set sizes
1090 module->tiling_callback(module, pipe, piece, &tiling);
1091 if (tiling.factor_cl < 0) tiling.factor_cl = tiling.factor; // default to CPU size if callback didn't set GPU
1092 if (tiling.maxbuf_cl < 0) tiling.maxbuf_cl = tiling.maxbuf;
1093
1094 /* does this module involve blending? */
1095 if(piece->blendop_data && ((dt_develop_blend_params_t *)piece->blendop_data)->mask_mode != DEVELOP_MASK_DISABLED)
1096 {
1097 /* get specific memory requirement for blending */
1098 dt_develop_tiling_t tiling_blendop = { 0 };
1099 tiling_callback_blendop(module, pipe, piece, &tiling_blendop);
1100
1101 /* aggregate in structure tiling */
1102 tiling.factor = fmax(tiling.factor, tiling_blendop.factor);
1103 tiling.factor_cl = fmax(tiling.factor_cl, tiling_blendop.factor);
1104 tiling.maxbuf = fmax(tiling.maxbuf, tiling_blendop.maxbuf);
1105 tiling.maxbuf_cl = fmax(tiling.maxbuf_cl, tiling_blendop.maxbuf);
1106 tiling.overhead = fmax(tiling.overhead, tiling_blendop.overhead);
1107 }
1108
1109 /* remark: we do not do tiling for blendop step, neither in opencl nor on cpu. if overall tiling
1110 requirements (maximum of module and blendop) require tiling for opencl path, then following blend
1111 step is anyhow done on cpu. we assume that blending itself will never require tiling in cpu path,
1112 because memory requirements will still be low enough. */
1113
1114 assert(tiling.factor > 0.0f);
1115 assert(tiling.factor_cl > 0.0f);
1116
1117 // Actual pixel processing for this module
1118 int error = 0;
1119 dt_times_t start;
1120 dt_get_times(&start);
1121
1122 const char *prev_module = dt_pixelpipe_cache_set_current_module(module ? module->op : NULL);
1123
1124#ifdef HAVE_OPENCL
1125 error = pixelpipe_process_on_GPU(pipe, piece, previous_piece, &tiling, &pixelpipe_flow,
1126 &cache_output,
1127 input_entry, output_entry);
1128#else
1129 error = pixelpipe_process_on_CPU(pipe, piece, previous_piece, &tiling, &pixelpipe_flow,
1130 &cache_output,
1131 input_entry, output_entry);
1132#endif
1133
1135 output = dt_pixel_cache_entry_get_data(output_entry);
1136
1137 _print_perf_debug(pipe, pixelpipe_flow, piece, module,
1138 (acquire_status != DT_DEV_PIXELPIPE_CACHE_WRITABLE_CREATED), &start);
1139
1140 if(dev->gui_attached) dev->progress.completed++;
1141
1142 if(error)
1143 {
1145 "[picker/rec] module=%s backend processing failed input_hash=%" PRIu64 " output_hash=%" PRIu64
1146 " input_cst=%d output_cst=%d roi_in=%dx%d roi_out=%dx%d\n",
1147 module->op, input_hash, hash, piece->dsc_in.cst, piece->dsc_out.cst,
1148 piece->roi_in.width, piece->roi_in.height, piece->roi_out.width, piece->roi_out.height);
1149 _trace_cache_owner(pipe, module, "error-cleanup", "input", input_hash, input, input_entry, FALSE);
1150 _trace_cache_owner(pipe, module, "error-cleanup", "output", hash, output, output_entry, FALSE);
1151 // Ensure we always release locks and cache references on error, otherwise cache eviction/GC will stall.
1156
1157 // No point in keeping garbled output
1161 return 1;
1162 }
1163
1164 // Publish the module output descriptor authored for this stage. The cache entry keeps the
1165 // descriptor of the pixels this module actually published, not the stale descriptor of its input.
1166 _trace_cache_owner(pipe, module, "publish", "output", hash, output, output_entry, FALSE);
1167 _trace_buffer_content(pipe, module, "publish", output, &piece->dsc_out, &piece->roi_out);
1168
1169 if(piece && allow_rekey_reuse && output_entry && !cache_output)
1170 {
1171 piece->cache_entry = *output_entry;
1172 }
1173 else
1175
1176 if(output_entry && output != NULL
1177 && ((pixelpipe_flow & PIXELPIPE_FLOW_PROCESSED_ON_CPU)
1178 || (pixelpipe_flow & PIXELPIPE_FLOW_PROCESSED_WITH_TILING)))
1179 {
1180 dt_dev_pixelpipe_gpu_flush_host_pinned_images(pipe, output, output_entry, "module output host rewrite");
1181 /* CPU/tiling processing rewrote the whole host buffer for this output. If the cache entry was rekeyed
1182 * from an older GPU stage, any cached device-only images still hanging off the same entry now point to
1183 * obsolete pixels. Drop them here so later mixed GPU/CPU modules cannot resurrect stale device payloads. */
1184 dt_pixel_cache_clmem_flush(output_entry);
1185 }
1186
1187 if(cl_mem_output != NULL)
1188 dt_dev_pixelpipe_gpu_clear_buffer(&cl_mem_output, output_entry, output,
1189 dt_dev_pixelpipe_cache_gpu_device_buffer(pipe, output_entry));
1190
1191 // Flag to throw away intermediate outputs as soon as the next module consumes them.
1192 // `cache_output` only means the backend had to keep a host-authoritative payload for this
1193 // stage (for example because the next module may need RAM or because the current stage ran
1194 // through an OpenCL cache path). In no-cache/bypass pipelines, that does not make the
1195 // published cacheline long-lived: once the downstream module takes its input ref, this
1196 // stage is transient and must disappear on release. Only the final published output needs
1197 // to survive long enough for dt_dev_pixelpipe_process() to promote it to the backbuffer,
1198 // otherwise thumbnail/export callers only see a missing exact-hit and fall back to invalid
1199 // placeholder pixels.
1200 const gboolean keep_final_output = (hash == dt_dev_pixelpipe_get_hash(pipe));
1201 if(_bypass_cache(pipe, piece) && !keep_final_output)
1203
1204 if(dev->gui_attached)
1205 {
1208 }
1209
1210 // From here on we only publish/inspect the finished output. Keep the writable lock strictly
1211 // around cacheline allocation and backend processing, then release it at one visible point
1212 // before the generic tail cleanup shared by darkroom and headless paths.
1214
1216
1217 // Decrease reference count on input and flush it if it was flagged for auto destroy previously
1218 _trace_cache_owner(pipe, module, "release", "input", input_hash, input, input_entry, FALSE);
1221
1222 // Print min/max/Nan in debug mode only
1223 if((darktable.unmuted & DT_DEBUG_NAN) && strcmp(module->op, "gamma") != 0 && output)
1224 {
1226 _print_nan_debug(pipe, cl_mem_output, output, &piece->roi_out, &piece->dsc_out, module);
1228 }
1229
1231
1232 *out_hash = hash;
1233 *out_piece = piece;
1234 return 0;
1235}
1236
1238{
1239 GList *nodes = g_list_last(pipe->nodes);
1241 while(strcmp(piece->module->op, op))
1242 {
1243 piece->enabled = 0;
1244 piece = NULL;
1245 nodes = g_list_previous(nodes);
1246 if(!nodes) break;
1247 piece = (dt_dev_pixelpipe_iop_t *)nodes->data;
1248 }
1249}
1250
1252{
1253 GList *nodes = pipe->nodes;
1255 while(strcmp(piece->module->op, op))
1256 {
1257 piece->enabled = 0;
1258 piece = NULL;
1259 nodes = g_list_next(nodes);
1260 if(!nodes) break;
1261 piece = (dt_dev_pixelpipe_iop_t *)nodes->data;
1262 }
1263}
1264
1265#define KILL_SWITCH_PIPE \
1266 if(dt_atomic_get_int(&pipe->shutdown)) \
1267 { \
1268 if(pipe->devid >= 0) \
1269 { \
1270 dt_opencl_unlock_device(pipe->devid); \
1271 pipe->devid = -1; \
1272 } \
1273 pipe->status = DT_DEV_PIXELPIPE_DIRTY; \
1274 if(pipe->forms) \
1275 { \
1276 g_list_free_full(pipe->forms, (void (*)(void *))dt_masks_free_form); \
1277 pipe->forms = NULL; \
1278 } \
1279 dt_pthread_mutex_unlock(&darktable.pipeline_threadsafe); \
1280 return 1; \
1281 }
1282
1283
1285{
1286 switch(error)
1287 {
1288 case 1:
1289 dt_print(DT_DEBUG_OPENCL, "[opencl] Opencl errors; disabling opencl for %s pipeline!\n", dt_pixelpipe_get_pipe_name(pipe->type));
1290 dt_control_log(_("Ansel discovered problems with your OpenCL setup; disabling OpenCL for %s pipeline!"), dt_pixelpipe_get_pipe_name(pipe->type));
1291 break;
1292 case 2:
1294 "[opencl] Too many opencl errors; disabling opencl for this session!\n");
1295 dt_control_log(_("Ansel discovered problems with your OpenCL setup; disabling OpenCL for this session!"));
1296 break;
1297 default:
1298 break;
1299 }
1300}
1301
1303{
1304 const uint64_t requested_hash = dt_dev_pixelpipe_get_hash(pipe);
1305 const uint64_t entry_hash = entry->hash;
1306
1307 _trace_cache_owner(pipe, NULL, "backbuf-update", "backbuf", requested_hash,
1308 entry ? entry->data : NULL, entry, FALSE);
1309
1310 if(requested_hash == DT_PIXELPIPE_CACHE_HASH_INVALID
1311 || entry_hash == DT_PIXELPIPE_CACHE_HASH_INVALID
1312 || entry_hash != requested_hash)
1313 {
1317 return;
1318 }
1319
1320 // Keep exactly one cache reference to the last valid output ("backbuf") for display.
1321 // This prevents the cache entry from being evicted while still in use by the GUI,
1322 // without leaking references on repeated cache hits.
1323 const gboolean hash_changed = (dt_dev_backbuf_get_hash(&pipe->backbuf) != entry_hash);
1324 if(hash_changed)
1325 {
1328 }
1329
1330 int bpp = 0;
1331 if(roi.width > 0 && roi.height > 0)
1332 bpp = (int)(dt_pixel_cache_entry_get_size(entry) / ((size_t)roi.width * (size_t)roi.height));
1333
1334 // Always refresh backbuf geometry/state, even when the cache key is unchanged.
1335 // Realtime drawing can update pixels in-place in the same cacheline, so width/height/history
1336 // must stay synchronized independently from key changes.
1337 dt_dev_set_backbuf(&pipe->backbuf, roi.width, roi.height, bpp, entry_hash,
1339}
1340
1342{
1344 {
1345 fprintf(stderr, "[memory] before pixelpipe process\n");
1347 }
1348
1350
1351 if(dev->gui_attached)
1352 {
1353 dev->color_picker.pending_module = NULL;
1354 dev->color_picker.pending_pipe = NULL;
1356 }
1357
1358 // Get the roi_out hash of all nodes.
1359 // Get the previous output size of the module, for cache invalidation.
1360 dt_dev_pixelpipe_get_roi_in(pipe, dev, roi);
1362 const guint pos = g_list_length(dev->iop);
1363
1364 void *buf = NULL;
1365
1366 // If the final output cacheline already matches the current pipeline state,
1367 // we can skip compute entirely. Darkroom pipes may still need the post-compute
1368 // sampling pass for histograms and picker reads.
1369 dt_pixel_cache_entry_t *entry = NULL;
1370 if(_requests_cache(pipe, NULL)
1372 -1, NULL)
1373 && buf != NULL)
1374 {
1375 _update_backbuf_cache_reference(pipe, roi, entry);
1376 return 0;
1377 }
1378
1379 // Flag backbuf as invalid
1381
1382 dt_print(DT_DEBUG_DEV, "[pixelpipe] Started %s pipeline recompute at %i×%i px\n",
1383 dt_pixelpipe_get_pipe_name(pipe->type), roi.width, roi.height);
1384
1385 // get a snapshot of the mask list
1387 pipe->forms = dt_masks_dup_forms_deep(dev->forms, NULL);
1389
1390 // go through the list of modules from the end:
1391 GList *pieces = g_list_last(pipe->nodes);
1392
1393 // Because it's possible here that we export at full resolution,
1394 // and our memory planning doesn't account for several concurrent pipelines
1395 // at full size, we allow only one pipeline at a time to run.
1396 // This is because wavelets decompositions and such use 6 copies,
1397 // so the RAM usage can go out of control here.
1399
1400 pipe->opencl_enabled = dt_opencl_update_settings(); // update enabled flag and profile from preferences
1401 pipe->devid = (pipe->opencl_enabled) ? dt_opencl_lock_device(pipe->type)
1402 : -1; // try to get/lock opencl resource
1403
1404 if(pipe->devid > -1) dt_opencl_events_reset(pipe->devid);
1405 dt_print(DT_DEBUG_OPENCL, "[pixelpipe_process] [%s] using device %d\n", dt_pixelpipe_get_pipe_name(pipe->type),
1406 pipe->devid);
1407
1409
1410 gboolean keep_running = TRUE;
1411 int runs = 0;
1412 int opencl_error = 0;
1413 int err = 0;
1414
1415 while(keep_running && runs < 3)
1416 {
1417 ++runs;
1418
1419 /* Mask preview is authored while the current run advances through blend.c.
1420 * Reset it for each retry so a stale state from a previous pass cannot leak
1421 * into the next recursion before the active module reaches its own blend. */
1423
1424#ifdef HAVE_OPENCL
1426#endif
1427
1429
1430 dt_times_t start;
1431 dt_get_times(&start);
1432 uint64_t final_hash = -1;
1433 const dt_dev_pixelpipe_iop_t *final_piece = NULL;
1434 err = dt_dev_pixelpipe_process_rec(pipe, dev, &final_hash, &final_piece, pieces, pos);
1435 (void)final_piece;
1436 gchar *msg = g_strdup_printf("[pixelpipe] %s internal pixel pipeline processing", dt_pixelpipe_get_pipe_name(pipe->type));
1437 dt_show_times(&start, msg);
1438 dt_free(msg);
1439
1440 // get status summary of opencl queue by checking the eventlist
1441 const int oclerr = (pipe->devid > -1) ? dt_opencl_events_flush(pipe->devid, TRUE) != 0 : 0;
1442
1443 // Check if we had opencl errors ....
1444 // remark: opencl errors can come in two ways: pipe->opencl_error is TRUE (and err is TRUE) OR oclerr is
1445 // TRUE
1446 keep_running = (oclerr || (err && pipe->opencl_error));
1447 if(keep_running)
1448 {
1449 // Log the error
1450 darktable.opencl->error_count++; // increase error count
1451 opencl_error = 1; // = any OpenCL error, next run goes to CPU
1452
1453 // Disable OpenCL for this pipe
1455 pipe->opencl_enabled = 0;
1456 pipe->opencl_error = 0;
1457 pipe->devid = -1;
1458
1460 {
1461 // Too many errors : dispable OpenCL for this session
1463 dt_capabilities_remove("opencl");
1464 opencl_error = 2; // = too many OpenCL errors, all runs go to CPU
1465 }
1466
1467 _print_opencl_errors(opencl_error, pipe);
1468 }
1469 else if(!dt_atomic_get_int(&pipe->shutdown))
1470 {
1471 // No opencl errors, no killswitch triggered: we should have a valid output buffer now.
1472 dt_pixel_cache_entry_t *final_entry = NULL;
1473 void *final_buf = NULL;
1475 &final_entry, pipe->devid, NULL)
1476 && final_buf != NULL)
1477 _update_backbuf_cache_reference(pipe, roi, final_entry);
1478 else
1480 "[picker/rec] final output cache missing pipe=%s hash=%" PRIu64 " history=%" PRIu64
1481 " devid=%d err=%d\n",
1483 dt_dev_pixelpipe_get_history_hash(pipe), pipe->devid, err);
1484
1485 // Note : the last output (backbuf) of the pixelpipe cache is internally locked
1486 // Whatever consuming it will need to unlock it.
1487 }
1488 }
1489
1491
1492 // release resources:
1493 if(pipe->forms)
1494 {
1495 g_list_free_full(pipe->forms, (void (*)(void *))dt_masks_free_form);
1496 pipe->forms = NULL;
1497 }
1498 if(pipe->devid >= 0)
1499 {
1501 pipe->devid = -1;
1502 }
1503
1504 // terminate
1506
1507 // If an intermediate module set that, be sure to reset it at the end
1508 pipe->flush_cache = FALSE;
1509 return err;
1510}
1511
1512// clang-format off
1513// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
1514// vim: shiftwidth=2 expandtab tabstop=2 cindent
1515// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
1516// clang-format on
static void error(char *msg)
Definition ashift_lsd.c:202
#define TRUE
Definition ashift_lsd.c:162
#define FALSE
Definition ashift_lsd.c:158
void dt_atomic_set_int(dt_atomic_int *var, int value)
Definition atomic.h:65
int dt_atomic_get_int(dt_atomic_int *var)
Definition atomic.h:66
atomic_int dt_atomic_int
Definition atomic.h:63
int levels(struct dt_imageio_module_data_t *data)
Definition avif.c:694
int width
Definition bilateral.h:1
int height
Definition bilateral.h:1
void tiling_callback_blendop(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe, const struct dt_dev_pixelpipe_iop_t *piece, struct dt_develop_tiling_t *tiling)
Definition blend.c:1512
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:184
@ DEVELOP_MASK_DISABLED
Definition blend.h:112
dt_iop_colorspace_type_t
Definition color_conversion.h:30
@ IOP_CS_RAW
Definition color_conversion.h:32
@ IOP_CS_LCH
Definition color_conversion.h:35
@ IOP_CS_JZCZHZ
Definition color_conversion.h:37
@ IOP_CS_RGB
Definition color_conversion.h:34
@ IOP_CS_HSL
Definition color_conversion.h:36
@ IOP_CS_LAB
Definition color_conversion.h:33
@ IOP_CS_NONE
Definition color_conversion.h:31
dt_iop_color_intent_t
Definition colorspaces.h:63
@ DT_INTENT_LAST
Definition colorspaces.h:68
dt_colorspaces_color_profile_type_t
Definition colorspaces.h:81
@ DT_COLORSPACE_NONE
Definition colorspaces.h:82
const float c
Definition colorspaces_inline_conversions.h:1365
const dt_aligned_pixel_t f
Definition colorspaces_inline_conversions.h:256
const float d
Definition colorspaces_inline_conversions.h:931
static const float const float const float min
Definition colorspaces_inline_conversions.h:667
const float r
Definition colorspaces_inline_conversions.h:1324
const float max
Definition colorspaces_inline_conversions.h:721
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
int type
Definition common/metadata.c:62
char * name
Definition common/metadata.c:61
void dt_control_log(const char *msg,...)
Definition control.c:530
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:630
void dt_show_times(const dt_times_t *start, const char *prefix)
Definition darktable.c:1568
darktable_t darktable
Definition darktable.c:178
void dt_print_mem_usage()
Definition darktable.c:1795
void dt_capabilities_remove(char *capability)
Definition darktable.c:1778
void dt_show_times_f(const dt_times_t *start, const char *prefix, const char *suffix,...)
Definition darktable.c:1582
void dt_print(dt_debug_thread_t thread, const char *msg,...)
Definition darktable.c:1530
#define UNKNOWN_IMAGE
Definition darktable.h:181
@ DT_DEBUG_OPENCL
Definition darktable.h:642
@ DT_DEBUG_PIPE
Definition darktable.h:661
@ DT_DEBUG_NAN
Definition darktable.h:646
@ DT_DEBUG_MEMORY
Definition darktable.h:644
@ DT_DEBUG_VERBOSE
Definition darktable.h:663
@ DT_DEBUG_CACHE
Definition darktable.h:636
@ DT_DEBUG_DEV
Definition darktable.h:638
@ DT_DEBUG_NOCACHE_REUSE
Definition darktable.h:665
static void dt_free_gpointer(gpointer ptr)
Definition darktable.h:387
#define dt_free(ptr)
Definition darktable.h:380
static void dt_get_times(dt_times_t *t)
Definition darktable.h:853
uint64_t dt_dev_pixelpipe_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 dev_pixelpipe.c:315
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 dev_pixelpipe.c:259
void dt_pixelpipe_get_global_hash(dt_dev_pixelpipe_t *pipe, dt_develop_t *dev)
Definition dev_pixelpipe.c:543
void dt_iop_buffer_dsc_update_bpp(dt_iop_buffer_dsc_t *dsc)
Definition develop/format.c:27
dt_iop_buffer_type_t
Definition develop/format.h:40
@ TYPE_FLOAT
Definition develop/format.h:42
@ TYPE_UNKNOWN
Definition develop/format.h:41
@ TYPE_UINT8
Definition develop/format.h:44
@ TYPE_UINT16
Definition develop/format.h:43
void dt_dev_set_backbuf(dt_backbuf_t *backbuf, const int width, const int height, const size_t bpp, const int64_t hash, const int64_t history_hash)
Definition develop.c:1709
gchar * dt_history_item_get_name(const struct dt_iop_module_t *module)
Definition develop.c:1354
@ DT_DEV_PIXELPIPE_DISPLAY_NONE
Definition develop.h:111
static int dt_pthread_mutex_unlock(dt_pthread_mutex_t *mutex) RELEASE(mutex) NO_THREAD_SAFETY_ANALYSIS
Definition dtpthread.h:374
static int dt_pthread_mutex_init(dt_pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr)
Definition dtpthread.h:359
static int dt_pthread_mutex_destroy(dt_pthread_mutex_t *mutex)
Definition dtpthread.h:379
#define dt_pthread_rwlock_unlock
Definition dtpthread.h:392
static int dt_pthread_mutex_lock(dt_pthread_mutex_t *mutex) ACQUIRE(mutex) NO_THREAD_SAFETY_ANALYSIS
Definition dtpthread.h:364
#define dt_pthread_rwlock_rdlock
Definition dtpthread.h:393
int bpp
Definition imageio/format/pdf.c:88
@ IMAGEIO_RGB
Definition imageio.h:69
@ IMAGEIO_INT8
Definition imageio.h:61
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:535
void dt_iop_nap(int32_t usec)
Definition imageop.c:2578
void dt_iop_cleanup_pipe(struct dt_iop_module_t *module, struct dt_dev_pixelpipe_t *pipe, struct dt_dev_pixelpipe_iop_t *piece)
Definition imageop.c:542
@ IOP_FLAGS_SUPPORTS_BLENDING
Definition imageop.h:144
@ IOP_TAG_DISTORT
Definition imageop.h:128
GList * dt_ioppr_iop_order_copy_deep(GList *iop_order_list)
Deep-copy an order list.
Definition iop_order.c:1669
GList * dt_masks_dup_forms_deep(GList *forms, dt_masks_form_t *form)
Duplicate the list of forms, replacing a single item by formid match.
Definition develop/masks/masks.c:718
void dt_masks_free_form(dt_masks_form_t *form)
Definition develop/masks/masks.c:1997
size_t size
Definition mipmap_cache.c:3
#define dt_mipmap_cache_get(A, B, C, D, E, F)
Definition mipmap_cache.h:120
@ DT_MIPMAP_BLOCKING
Definition mipmap_cache.h:60
#define dt_mipmap_cache_release(A, B)
Definition mipmap_cache.h:142
dt_mipmap_size_t
Definition mipmap_cache.h:40
Definition tiling.py:1
static void dt_opencl_events_reset(const int devid)
Definition opencl.h:626
static void dt_opencl_unlock_device(const int dev)
Definition opencl.h:538
static int dt_opencl_update_settings(void)
Definition opencl.h:594
static void dt_opencl_check_tuning(const int devid)
Definition opencl.h:607
#define DT_OPENCL_MAX_ERRORS
Definition opencl.h:49
static int dt_opencl_lock_device(const int dev)
Definition opencl.h:534
static int dt_opencl_events_flush(const int devid, const int reset)
Definition opencl.h:632
void dt_pixelpipe_raster_cleanup(GHashTable *raster_masks)
Definition pixelpipe.c:55
GHashTable * dt_pixelpipe_raster_alloc()
Definition pixelpipe.c:50
@ DT_REQUEST_ON
Definition pixelpipe.h:48
@ DT_REQUEST_ONLY_IN_GUI
Definition pixelpipe.h:49
dt_dev_pixelpipe_type_t
Definition pixelpipe.h:36
@ DT_DEV_PIXELPIPE_THUMBNAIL
Definition pixelpipe.h:41
@ DT_DEV_PIXELPIPE_EXPORT
Definition pixelpipe.h:38
@ DT_DEV_PIXELPIPE_PREVIEW
Definition pixelpipe.h:40
@ DT_DEV_PIXELPIPE_FULL
Definition pixelpipe.h:39
void dt_pixel_cache_clmem_flush(dt_pixel_cache_entry_t *entry)
Definition pixelpipe_cache.c:735
void * dt_pixel_cache_entry_get_data(dt_pixel_cache_entry_t *entry)
Definition pixelpipe_cache.c:1081
void dt_dev_pixelpipe_cache_ref_count_entry(dt_dev_pixelpipe_cache_t *cache, 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:1871
void dt_dev_pixelpipe_cache_print(dt_dev_pixelpipe_cache_t *cache)
Definition pixelpipe_cache.c:2116
void dt_dev_pixelpipe_cache_unref_hash(dt_dev_pixelpipe_cache_t *cache, const uint64_t hash)
Find the entry matching hash, and decrease its ref_count if found.
Definition pixelpipe_cache.c:2016
void dt_dev_pixelpipe_cache_flag_auto_destroy(dt_dev_pixelpipe_cache_t *cache, dt_pixel_cache_entry_t *cache_entry)
Flag the cache entry as "auto_destroy". This is useful for short-lived/disposable cache entries,...
Definition pixelpipe_cache.c:1912
void dt_dev_pixelpipe_cache_auto_destroy_apply(dt_dev_pixelpipe_cache_t *cache, dt_pixel_cache_entry_t *cache_entry)
Free the entry if it has the flag "auto_destroy". See dt_dev_pixelpipe_cache_flag_auto_destroy()....
Definition pixelpipe_cache.c:1928
void dt_dev_pixelpipe_cache_flush_clmem(dt_dev_pixelpipe_cache_t *cache, const int devid, void *keep)
Release cached OpenCL buffers for a device (-1 for all).
Definition pixelpipe_cache.c:461
gboolean dt_dev_pixelpipe_cache_peek(dt_dev_pixelpipe_cache_t *cache, const uint64_t hash, void **data, dt_pixel_cache_entry_t **entry, const int preferred_devid, void **cl_mem_output)
Non-owning lookup of an existing cache line.
Definition pixelpipe_cache.c:1704
dt_pixel_cache_entry_t * dt_dev_pixelpipe_cache_get_entry(dt_dev_pixelpipe_cache_t *cache, const uint64_t hash)
Get an internal reference to the cache entry matching hash. If you are going to access this entry mor...
Definition pixelpipe_cache.c:136
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, const gboolean alloc, void **data, dt_pixel_cache_entry_t **entry)
Get a cache line from the cache.
Definition pixelpipe_cache.c:1438
int dt_dev_pixelpipe_cache_remove(dt_dev_pixelpipe_cache_t *cache, 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:209
dt_dev_pixelpipe_cache_writable_status_t dt_dev_pixelpipe_cache_get_writable(dt_dev_pixelpipe_cache_t *cache, const uint64_t hash, const size_t size, const char *name, const int id, const gboolean alloc, const gboolean allow_rekey_reuse, const dt_pixel_cache_entry_t *reuse_hint, void **data, dt_pixel_cache_entry_t **entry)
Definition pixelpipe_cache.c:1508
void dt_dev_pixelpipe_cache_wrlock_entry(dt_dev_pixelpipe_cache_t *cache, gboolean lock, dt_pixel_cache_entry_t *cache_entry)
Lock or release the write lock on the entry.
Definition pixelpipe_cache.c:1880
size_t dt_pixel_cache_entry_get_size(dt_pixel_cache_entry_t *entry)
Peek the size (in bytes) reserved for the host buffer of a cache entry.
Definition pixelpipe_cache.c:1086
void dt_dev_pixelpipe_cache_rdlock_entry(dt_dev_pixelpipe_cache_t *cache, gboolean lock, dt_pixel_cache_entry_t *cache_entry)
Lock or release the read lock on the entry.
Definition pixelpipe_cache.c:1896
const char * dt_pixelpipe_cache_set_current_module(const char *module)
Set the current module name for cache diagnostics (thread-local).
Definition pixelpipe_cache.c:76
Pixelpipe cache for storing intermediate results in the pixelpipe.
#define DT_PIXELPIPE_CACHE_HASH_INVALID
Definition pixelpipe_cache.h:41
dt_dev_pixelpipe_cache_writable_status_t
Definition pixelpipe_cache.h:69
@ DT_DEV_PIXELPIPE_CACHE_WRITABLE_REKEYED
Definition pixelpipe_cache.h:73
@ DT_DEV_PIXELPIPE_CACHE_WRITABLE_CREATED
Definition pixelpipe_cache.h:72
@ DT_DEV_PIXELPIPE_CACHE_WRITABLE_EXACT_HIT
Definition pixelpipe_cache.h:71
int pixelpipe_process_on_CPU(dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, const dt_dev_pixelpipe_iop_t *previous_piece, dt_develop_tiling_t *tiling, dt_pixelpipe_flow_t *pixelpipe_flow, gboolean *const cache_output, dt_pixel_cache_entry_t *input_entry, dt_pixel_cache_entry_t *output_entry)
Definition pixelpipe_cpu.c:15
int pixelpipe_process_on_GPU(dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, const dt_dev_pixelpipe_iop_t *previous_piece, dt_develop_tiling_t *tiling, dt_pixelpipe_flow_t *pixelpipe_flow, gboolean *const cache_output, dt_pixel_cache_entry_t *input_entry, dt_pixel_cache_entry_t *output_entry)
Definition pixelpipe_gpu.c:728
void dt_dev_pixelpipe_gpu_clear_buffer(void **cl_mem_buffer, dt_pixel_cache_entry_t *cache_entry, void *host_ptr, gboolean allow_reuse)
Definition pixelpipe_gpu.c:18
void dt_dev_pixelpipe_gpu_flush_host_pinned_images(dt_dev_pixelpipe_t *pipe, void *host_ptr, dt_pixel_cache_entry_t *cache_entry, const char *reason)
Definition pixelpipe_gpu.c:24
GUI-side histogram sampling from preview cache.
dt_pixelpipe_blend_transform_t dt_dev_pixelpipe_transform_for_blend(const dt_iop_module_t *const self, const dt_dev_pixelpipe_iop_t *const piece, const dt_iop_buffer_dsc_t *const output_dsc)
Definition pixelpipe_hb.c:631
static void _trace_buffer_content(const dt_dev_pixelpipe_t *pipe, const dt_iop_module_t *module, const char *phase, const void *buffer, const dt_iop_buffer_dsc_t *format, const dt_iop_roi_t *roi)
Definition pixelpipe_hb.c:120
void dt_dev_pixelpipe_disable_before(dt_dev_pixelpipe_t *pipe, const char *op)
Definition pixelpipe_hb.c:1251
int dt_dev_pixelpipe_init_preview(dt_dev_pixelpipe_t *pipe)
Definition pixelpipe_hb.c:422
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:482
static gboolean _is_focused_realtime_gui_module(const dt_dev_pixelpipe_t *pipe, const dt_develop_t *dev, const dt_iop_module_t *module)
Definition pixelpipe_hb.c:242
static dt_iop_roi_t * _get_first_roi(dt_dev_pixelpipe_t *pipe)
Definition pixelpipe_hb.c:777
int dt_dev_pixelpipe_process(dt_dev_pixelpipe_t *pipe, dt_develop_t *dev, dt_iop_roi_t roi)
Definition pixelpipe_hb.c:1341
void dt_dev_pixelpipe_reset_reentry(dt_dev_pixelpipe_t *pipe)
Definition pixelpipe_hb.c:567
int dt_dev_pixelpipe_init_cached(dt_dev_pixelpipe_t *pipe)
Definition pixelpipe_hb.c:444
static void _update_backbuf_cache_reference(dt_dev_pixelpipe_t *pipe, dt_iop_roi_t roi, dt_pixel_cache_entry_t *entry)
Definition pixelpipe_hb.c:1302
gboolean dt_dev_pixelpipe_has_reentry(dt_dev_pixelpipe_t *pipe)
Definition pixelpipe_hb.c:562
void dt_dev_pixelpipe_disable_after(dt_dev_pixelpipe_t *pipe, const char *op)
Definition pixelpipe_hb.c:1237
int dt_dev_pixelpipe_init_export(dt_dev_pixelpipe_t *pipe, int levels, gboolean store_masks)
Definition pixelpipe_hb.c:396
int dt_dev_pixelpipe_init_thumbnail(dt_dev_pixelpipe_t *pipe)
Definition pixelpipe_hb.c:406
int dt_dev_pixelpipe_init_dummy(dt_dev_pixelpipe_t *pipe)
Definition pixelpipe_hb.c:414
gboolean dt_dev_pixelpipe_cache_gpu_device_buffer(const dt_dev_pixelpipe_t *pipe, const dt_pixel_cache_entry_t *cache_entry)
Definition pixelpipe_hb.c:251
gboolean dt_dev_pixelpipe_get_realtime(const dt_dev_pixelpipe_t *pipe)
Definition pixelpipe_hb.c:477
static const char * _debug_type_to_string(const dt_iop_buffer_type_t type)
Definition pixelpipe_hb.c:344
static const char * _debug_cst_to_string(const int cst)
Definition pixelpipe_hb.c:321
#define KILL_SWITCH_ABORT
Definition pixelpipe_hb.c:650
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:492
void dt_dev_pixelpipe_create_nodes(dt_dev_pixelpipe_t *pipe, dt_develop_t *dev)
Definition pixelpipe_hb.c:593
static int _abort_module_shutdown_cleanup(dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece, dt_iop_module_t *module, const uint64_t input_hash, const void *input, dt_pixel_cache_entry_t *input_entry, const uint64_t output_hash, void **output, void **cl_mem_output, dt_pixel_cache_entry_t *output_entry)
Definition pixelpipe_hb.c:206
char * dt_pixelpipe_get_pipe_name(dt_dev_pixelpipe_type_t pipe_type)
Definition pixelpipe_hb.c:259
static void _print_opencl_errors(int error, dt_dev_pixelpipe_t *pipe)
Definition pixelpipe_hb.c:1284
static void _trace_cache_owner(const dt_dev_pixelpipe_t *pipe, const dt_iop_module_t *module, const char *phase, const char *slot, const uint64_t requested_hash, const void *buffer, const dt_pixel_cache_entry_t *entry, const gboolean verbose)
Definition pixelpipe_hb.c:94
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)
Definition pixelpipe_hb.c:703
static int _init_base_buffer(dt_dev_pixelpipe_t *pipe)
Definition pixelpipe_hb.c:790
#define KILL_SWITCH_PIPE
Definition pixelpipe_hb.c:1265
static int dt_dev_pixelpipe_process_rec(dt_dev_pixelpipe_t *pipe, dt_develop_t *dev, uint64_t *out_hash, const dt_dev_pixelpipe_iop_t **out_piece, GList *pieces, int pos)
Definition pixelpipe_hb.c:885
void dt_dev_pixelpipe_cleanup(dt_dev_pixelpipe_t *pipe)
Definition pixelpipe_hb.c:501
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:549
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:283
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, const gboolean recycled_output_cacheline, dt_times_t *start)
Definition pixelpipe_hb.c:671
int dt_dev_pixelpipe_init(dt_dev_pixelpipe_t *pipe)
Definition pixelpipe_hb.c:434
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:301
void dt_dev_pixelpipe_debug_dump_module_io(dt_dev_pixelpipe_t *pipe, dt_iop_module_t *module, const char *stage, const gboolean is_cl, const dt_iop_buffer_dsc_t *in_dsc, const dt_iop_buffer_dsc_t *out_dsc, const dt_iop_roi_t *roi_in, const dt_iop_roi_t *roi_out, const size_t in_bpp, const size_t out_bpp, const int cst_before, const int cst_after)
Definition pixelpipe_hb.c:360
#define KILL_SWITCH_AND_FLUSH_CACHE
Definition pixelpipe_hb.c:664
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:535
void dt_dev_pixelpipe_set_realtime(dt_dev_pixelpipe_t *pipe, gboolean state)
Definition pixelpipe_hb.c:471
void dt_dev_pixelpipe_cleanup_nodes(dt_dev_pixelpipe_t *pipe)
Definition pixelpipe_hb.c:574
static void dt_dev_pixelpipe_set_hash(dt_dev_pixelpipe_t *pipe, const uint64_t hash)
Definition pixelpipe_hb.h:355
static uint64_t dt_dev_pixelpipe_get_hash(const dt_dev_pixelpipe_t *pipe)
Definition pixelpipe_hb.h:350
@ DT_DEV_PIPE_UNCHANGED
Definition pixelpipe_hb.h:164
static uint64_t dt_dev_pixelpipe_get_history_hash(const dt_dev_pixelpipe_t *pipe)
Definition pixelpipe_hb.h:360
static void dt_dev_pixelpipe_set_history_hash(dt_dev_pixelpipe_t *pipe, const uint64_t history_hash)
Definition pixelpipe_hb.h:365
static uint64_t dt_dev_backbuf_get_hash(const dt_backbuf_t *backbuf)
Definition pixelpipe_hb.h:195
static void dt_dev_pixelpipe_set_changed(dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_change_t v)
Definition pixelpipe_hb.h:375
@ DT_DEV_PIXELPIPE_DIRTY
Definition pixelpipe_hb.h:174
void dt_dev_clear_rawdetail_mask(dt_dev_pixelpipe_t *pipe)
Definition pixelpipe_rawdetail.c:11
dt_pixelpipe_flow_t
Definition pixelpipe_process.h:14
@ PIXELPIPE_FLOW_HISTOGRAM_ON_GPU
Definition pixelpipe_process.h:18
@ PIXELPIPE_FLOW_HISTOGRAM_NONE
Definition pixelpipe_process.h:16
@ PIXELPIPE_FLOW_PROCESSED_ON_CPU
Definition pixelpipe_process.h:19
@ PIXELPIPE_FLOW_PROCESSED_WITH_TILING
Definition pixelpipe_process.h:21
@ PIXELPIPE_FLOW_PROCESSED_ON_GPU
Definition pixelpipe_process.h:20
@ PIXELPIPE_FLOW_NONE
Definition pixelpipe_process.h:15
@ PIXELPIPE_FLOW_BLENDED_ON_CPU
Definition pixelpipe_process.h:22
@ PIXELPIPE_FLOW_HISTOGRAM_ON_CPU
Definition pixelpipe_process.h:17
@ PIXELPIPE_FLOW_BLENDED_ON_GPU
Definition pixelpipe_process.h:23
static void _reset_piece_cache_entry(dt_dev_pixelpipe_iop_t *piece)
Drop the writable-reuse snapshot attached to a pipeline piece.
Definition pixelpipe_process.h:73
static gboolean _requests_cache(const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece)
Tell whether cache lookups and published cachelines are allowed for the current pipeline state.
Definition pixelpipe_process.h:59
static gboolean _bypass_cache(const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece)
Tell whether the current pipeline state forbids keeping this module output in cache.
Definition pixelpipe_process.h:45
dt_pixelpipe_blend_transform_t
Definition pixelpipe_process.h:27
@ DT_DEV_PIXELPIPE_BLEND_TRANSFORM_INPUT
Definition pixelpipe_process.h:29
@ DT_DEV_PIXELPIPE_BLEND_TRANSFORM_NONE
Definition pixelpipe_process.h:28
@ DT_DEV_PIXELPIPE_BLEND_TRANSFORM_OUTPUT
Definition pixelpipe_process.h:30
Raster-mask retrieval and transport through already-processed pipeline nodes.
Raw-detail mask production and transport helpers.
unsigned __int64 uint64_t
Definition strptime.c:74
struct dt_dev_pixelpipe_cache_t * pixelpipe_cache
Definition darktable.h:718
struct dt_mipmap_cache_t * mipmap_cache
Definition darktable.h:704
struct dt_opencl_t * opencl
Definition darktable.h:713
int32_t unmuted
Definition darktable.h:688
dt_pthread_mutex_t pipeline_threadsafe
Definition darktable.h:736
char * main_message
Definition darktable.h:766
Definition pixelpipe_hb.h:95
gboolean enabled
Definition pixelpipe_hb.h:110
dt_dev_request_flags_t request_histogram
Definition pixelpipe_hb.h:112
uint64_t global_hash
Definition pixelpipe_hb.h:123
dt_iop_buffer_dsc_t dsc_in
Definition pixelpipe_hb.h:140
struct dt_iop_module_t *void * data
Definition pixelpipe_hb.h:96
dt_iop_roi_t roi_in
Definition pixelpipe_hb.h:130
GHashTable * raster_masks
Definition pixelpipe_hb.h:159
void * blendop_data
Definition pixelpipe_hb.h:109
Definition pixelpipe_hb.h:216
dt_colorspaces_color_profile_type_t icc_type
Definition pixelpipe_hb.h:296
int iwidth
Definition pixelpipe_hb.h:222
int opencl_error
Definition pixelpipe_hb.h:275
gboolean gui_observable_source
Definition pixelpipe_hb.h:288
gchar * icc_filename
Definition pixelpipe_hb.h:297
uint64_t last_history_hash
Definition pixelpipe_hb.h:309
dt_pthread_mutex_t busy_mutex
Definition pixelpipe_hb.h:251
gboolean flush_cache
Definition pixelpipe_hb.h:335
int mask_display
Definition pixelpipe_hb.h:279
GList * nodes
Definition pixelpipe_hb.h:237
dt_dev_pixelpipe_status_t status
Definition pixelpipe_hb.h:227
dt_imageio_levels_t levels
Definition pixelpipe_hb.h:290
dt_atomic_int realtime
Definition pixelpipe_hb.h:271
dt_backbuf_t backbuf
Definition pixelpipe_hb.h:242
gboolean reentry
Definition pixelpipe_hb.h:323
dt_mipmap_size_t size
Definition pixelpipe_hb.h:219
dt_iop_color_intent_t icc_intent
Definition pixelpipe_hb.h:298
dt_image_t image
Definition pixelpipe_hb.h:294
dt_atomic_int shutdown
Definition pixelpipe_hb.h:265
uint64_t reentry_hash
Definition pixelpipe_hb.h:329
int opencl_enabled
Definition pixelpipe_hb.h:273
dt_dev_pixelpipe_type_t type
Definition pixelpipe_hb.h:284
int32_t imgid
Definition pixelpipe_hb.h:218
gboolean no_cache
Definition pixelpipe_hb.h:343
gboolean store_all_raster_masks
Definition pixelpipe_hb.h:304
int iheight
Definition pixelpipe_hb.h:222
GList * forms
Definition pixelpipe_hb.h:302
int devid
Definition pixelpipe_hb.h:292
int output_imgid
Definition pixelpipe_hb.h:259
GList * iop_order_list
Definition pixelpipe_hb.h:300
Definition blend.h:198
Definition develop.h:155
int32_t gui_attached
Definition develop.h:158
GList * iop_order_list
Definition develop.h:269
dt_image_t image_storage
Definition develop.h:243
struct dt_develop_t::@19 color_picker
Authoritative darkroom color-picker state.
GList * iop
Definition develop.h:263
struct dt_iop_module_t * pending_module
Definition develop.h:369
int completed
Definition develop.h:455
struct dt_iop_module_t * gui_module
Definition develop.h:161
struct dt_dev_pixelpipe_t * pending_pipe
Definition develop.h:370
dt_pthread_rwlock_t masks_mutex
Definition develop.h:299
struct dt_develop_t::@26 progress
uint64_t piece_hash
Definition develop.h:367
int total
Definition develop.h:455
GList * forms
Definition develop.h:287
Definition tiling.h:39
float factor
Definition tiling.h:41
unsigned overhead
Definition tiling.h:49
float maxbuf
Definition tiling.h:45
dt_iop_buffer_dsc_t dsc
Definition common/image.h:297
Definition develop/format.h:48
int cst
Definition develop/format.h:76
unsigned int channels
Definition develop/format.h:50
size_t bpp
Definition develop/format.h:54
dt_iop_buffer_type_t datatype
Definition develop/format.h:52
Definition imageop.h:216
GModule *dt_dev_operation_t op
Definition imageop.h:226
Definition imageop.h:67
int x
Definition imageop.h:68
int width
Definition imageop.h:68
int height
Definition imageop.h:68
int y
Definition imageop.h:68
Definition mipmap_cache.h:68
int32_t height
Definition mipmap_cache.h:71
uint8_t * buf
Definition mipmap_cache.h:73
int32_t width
Definition mipmap_cache.h:71
int error_count
Definition opencl.h:512
int stopped
Definition opencl.h:511
Definition pixelpipe_cache.h:86
uint64_t hash
Definition pixelpipe_cache.h:87
void * data
Definition pixelpipe_cache.h:89
Definition darktable.h:770
#define MIN(a, b)
Definition thinplate.c:32
#define MAX(a, b)
Definition thinplate.c:29