1 /*
2     This file is part of darktable,
3     Copyright (C) 2009-2021 darktable developers.
4 
5     darktable is free software: you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation, either version 3 of the License, or
8     (at your option) any later version.
9 
10     darktable is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14 
15     You should have received a copy of the GNU General Public License
16     along with darktable.  If not, see <http://www.gnu.org/licenses/>.
17 */
18 #include "common/color_picker.h"
19 #include "common/colorspaces.h"
20 #include "common/histogram.h"
21 #include "common/imageio.h"
22 #include "common/opencl.h"
23 #include "common/iop_order.h"
24 #include "control/control.h"
25 #include "control/signal.h"
26 #include "develop/blend.h"
27 #include "develop/format.h"
28 #include "develop/imageop_math.h"
29 #include "develop/pixelpipe.h"
30 #include "develop/tiling.h"
31 #include "develop/masks.h"
32 #include "gui/gtk.h"
33 #include "libs/colorpicker.h"
34 #include "libs/lib.h"
35 #include "gui/color_picker_proxy.h"
36 
37 #include <assert.h>
38 #include <math.h>
39 #include <stdint.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <strings.h>
43 #include <unistd.h>
44 
45 typedef enum dt_pixelpipe_flow_t
46 {
47   PIXELPIPE_FLOW_NONE = 0,
48   PIXELPIPE_FLOW_HISTOGRAM_NONE = 1 << 0,
49   PIXELPIPE_FLOW_HISTOGRAM_ON_CPU = 1 << 1,
50   PIXELPIPE_FLOW_HISTOGRAM_ON_GPU = 1 << 2,
51   PIXELPIPE_FLOW_PROCESSED_ON_CPU = 1 << 3,
52   PIXELPIPE_FLOW_PROCESSED_ON_GPU = 1 << 4,
53   PIXELPIPE_FLOW_PROCESSED_WITH_TILING = 1 << 5,
54   PIXELPIPE_FLOW_BLENDED_ON_CPU = 1 << 6,
55   PIXELPIPE_FLOW_BLENDED_ON_GPU = 1 << 7
56 } dt_pixelpipe_flow_t;
57 
58 typedef enum dt_pixelpipe_picker_source_t
59 {
60   PIXELPIPE_PICKER_INPUT = 0,
61   PIXELPIPE_PICKER_OUTPUT = 1
62 } dt_pixelpipe_picker_source_t;
63 
64 #include "develop/pixelpipe_cache.c"
65 
66 static void get_output_format(dt_iop_module_t *module, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece,
67                               dt_develop_t *dev, dt_iop_buffer_dsc_t *dsc);
68 
_pipe_type_to_str(int pipe_type)69 static char *_pipe_type_to_str(int pipe_type)
70 {
71   const gboolean fast = (pipe_type & DT_DEV_PIXELPIPE_FAST) == DT_DEV_PIXELPIPE_FAST;
72   char *r = NULL;
73 
74   switch(pipe_type & DT_DEV_PIXELPIPE_ANY)
75   {
76     case DT_DEV_PIXELPIPE_PREVIEW:
77       if(fast)
78         r = "preview/fast";
79       else
80         r = "preview";
81       break;
82     case DT_DEV_PIXELPIPE_PREVIEW2:
83       if(fast)
84         r = "preview2/fast";
85       else
86         r = "preview2";
87       break;
88     case DT_DEV_PIXELPIPE_FULL:
89       if(fast)
90       r = "full";
91       r = "full";
92       break;
93     case DT_DEV_PIXELPIPE_THUMBNAIL:
94       if(fast)
95         r = "thumbnail/fast";
96       else
97         r = "thumbnail";
98       break;
99     case DT_DEV_PIXELPIPE_EXPORT:
100       if(fast)
101         r = "export/fast";
102       else
103         r = "export";
104       break;
105     default:
106       r = "unknown";
107   }
108   return r;
109 }
110 
dt_dev_pixelpipe_init_export(dt_dev_pixelpipe_t * pipe,int32_t width,int32_t height,int levels,gboolean store_masks)111 int dt_dev_pixelpipe_init_export(dt_dev_pixelpipe_t *pipe, int32_t width, int32_t height, int levels,
112                                  gboolean store_masks)
113 {
114   const int res = dt_dev_pixelpipe_init_cached(pipe, sizeof(float) * 4 * width * height, 2);
115   pipe->type = DT_DEV_PIXELPIPE_EXPORT;
116   pipe->levels = levels;
117   pipe->store_all_raster_masks = store_masks;
118   return res;
119 }
120 
dt_dev_pixelpipe_init_thumbnail(dt_dev_pixelpipe_t * pipe,int32_t width,int32_t height)121 int dt_dev_pixelpipe_init_thumbnail(dt_dev_pixelpipe_t *pipe, int32_t width, int32_t height)
122 {
123   const int res = dt_dev_pixelpipe_init_cached(pipe, sizeof(float) * 4 * width * height, 2);
124   pipe->type = DT_DEV_PIXELPIPE_THUMBNAIL;
125   return res;
126 }
127 
dt_dev_pixelpipe_init_dummy(dt_dev_pixelpipe_t * pipe,int32_t width,int32_t height)128 int dt_dev_pixelpipe_init_dummy(dt_dev_pixelpipe_t *pipe, int32_t width, int32_t height)
129 {
130   const int res = dt_dev_pixelpipe_init_cached(pipe, sizeof(float) * 4 * width * height, 0);
131   pipe->type = DT_DEV_PIXELPIPE_THUMBNAIL;
132   return res;
133 }
134 
dt_dev_pixelpipe_init_preview(dt_dev_pixelpipe_t * pipe)135 int dt_dev_pixelpipe_init_preview(dt_dev_pixelpipe_t *pipe)
136 {
137   // don't know which buffer size we're going to need, set to 0 (will be alloced on demand)
138   const int res = dt_dev_pixelpipe_init_cached(pipe, 0, 8);
139   pipe->type = DT_DEV_PIXELPIPE_PREVIEW;
140   return res;
141 }
142 
dt_dev_pixelpipe_init_preview2(dt_dev_pixelpipe_t * pipe)143 int dt_dev_pixelpipe_init_preview2(dt_dev_pixelpipe_t *pipe)
144 {
145   // don't know which buffer size we're going to need, set to 0 (will be alloced on demand)
146   const int res = dt_dev_pixelpipe_init_cached(pipe, 0, 5);
147   pipe->type = DT_DEV_PIXELPIPE_PREVIEW2;
148   return res;
149 }
150 
dt_dev_pixelpipe_init(dt_dev_pixelpipe_t * pipe)151 int dt_dev_pixelpipe_init(dt_dev_pixelpipe_t *pipe)
152 {
153   // don't know which buffer size we're going to need, set to 0 (will be alloced on demand)
154   const int res = dt_dev_pixelpipe_init_cached(pipe, 0, 8);
155   pipe->type = DT_DEV_PIXELPIPE_FULL;
156   return res;
157 }
158 
dt_dev_pixelpipe_init_cached(dt_dev_pixelpipe_t * pipe,size_t size,int32_t entries)159 int dt_dev_pixelpipe_init_cached(dt_dev_pixelpipe_t *pipe, size_t size, int32_t entries)
160 {
161   pipe->devid = -1;
162   pipe->changed = DT_DEV_PIPE_UNCHANGED;
163   pipe->processed_width = pipe->backbuf_width = pipe->iwidth = 0;
164   pipe->processed_height = pipe->backbuf_height = pipe->iheight = 0;
165   pipe->nodes = NULL;
166   pipe->backbuf_size = size;
167   if(!dt_dev_pixelpipe_cache_init(&(pipe->cache), entries, pipe->backbuf_size)) return 0;
168   pipe->cache_obsolete = 0;
169   pipe->backbuf = NULL;
170   pipe->backbuf_scale = 0.0f;
171   pipe->backbuf_zoom_x = 0.0f;
172   pipe->backbuf_zoom_y = 0.0f;
173 
174   pipe->output_backbuf = NULL;
175   pipe->output_backbuf_width = 0;
176   pipe->output_backbuf_height = 0;
177   pipe->output_imgid = 0;
178 
179   pipe->rawdetail_mask_data = NULL;
180   pipe->want_detail_mask = DT_DEV_DETAIL_MASK_NONE;
181 
182   pipe->processing = 0;
183   dt_atomic_set_int(&pipe->shutdown,FALSE);
184   pipe->opencl_error = 0;
185   pipe->tiling = 0;
186   pipe->mask_display = DT_DEV_PIXELPIPE_DISPLAY_NONE;
187   pipe->bypass_blendif = 0;
188   pipe->input_timestamp = 0;
189   pipe->levels = IMAGEIO_RGB | IMAGEIO_INT8;
190   dt_pthread_mutex_init(&(pipe->backbuf_mutex), NULL);
191   dt_pthread_mutex_init(&(pipe->busy_mutex), NULL);
192   pipe->icc_type = DT_COLORSPACE_NONE;
193   pipe->icc_filename = NULL;
194   pipe->icc_intent = DT_INTENT_LAST;
195   pipe->iop = NULL;
196   pipe->iop_order_list = NULL;
197   pipe->forms = NULL;
198   pipe->store_all_raster_masks = FALSE;
199   pipe->work_profile_info = NULL;
200   pipe->input_profile_info = NULL;
201   pipe->output_profile_info = NULL;
202 
203   return 1;
204 }
205 
dt_dev_pixelpipe_set_input(dt_dev_pixelpipe_t * pipe,dt_develop_t * dev,float * input,int width,int height,float iscale)206 void dt_dev_pixelpipe_set_input(dt_dev_pixelpipe_t *pipe, dt_develop_t *dev, float *input, int width, int height,
207                                 float iscale)
208 {
209   pipe->iwidth = width;
210   pipe->iheight = height;
211   pipe->iscale = iscale;
212   pipe->input = input;
213   pipe->image = dev->image_storage;
214   get_output_format(NULL, pipe, NULL, dev, &pipe->dsc);
215 }
216 
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)217 void dt_dev_pixelpipe_set_icc(dt_dev_pixelpipe_t *pipe, dt_colorspaces_color_profile_type_t icc_type,
218                               const gchar *icc_filename, dt_iop_color_intent_t icc_intent)
219 {
220   pipe->icc_type = icc_type;
221   g_free(pipe->icc_filename);
222   pipe->icc_filename = g_strdup(icc_filename ? icc_filename : "");
223   pipe->icc_intent = icc_intent;
224 }
225 
dt_dev_pixelpipe_cleanup(dt_dev_pixelpipe_t * pipe)226 void dt_dev_pixelpipe_cleanup(dt_dev_pixelpipe_t *pipe)
227 {
228   dt_pthread_mutex_lock(&pipe->backbuf_mutex);
229   pipe->backbuf = NULL;
230   // blocks while busy and sets shutdown bit:
231   dt_dev_pixelpipe_cleanup_nodes(pipe);
232   // so now it's safe to clean up cache:
233   dt_dev_pixelpipe_cache_cleanup(&(pipe->cache));
234   dt_pthread_mutex_unlock(&pipe->backbuf_mutex);
235   dt_pthread_mutex_destroy(&(pipe->backbuf_mutex));
236   dt_pthread_mutex_destroy(&(pipe->busy_mutex));
237   pipe->icc_type = DT_COLORSPACE_NONE;
238   g_free(pipe->icc_filename);
239   pipe->icc_filename = NULL;
240 
241   g_free(pipe->output_backbuf);
242   pipe->output_backbuf = NULL;
243   pipe->output_backbuf_width = 0;
244   pipe->output_backbuf_height = 0;
245   pipe->output_imgid = 0;
246 
247   dt_dev_clear_rawdetail_mask(pipe);
248 
249   if(pipe->forms)
250   {
251     g_list_free_full(pipe->forms, (void (*)(void *))dt_masks_free_form);
252     pipe->forms = NULL;
253   }
254 }
255 
dt_dev_pixelpipe_cleanup_nodes(dt_dev_pixelpipe_t * pipe)256 void dt_dev_pixelpipe_cleanup_nodes(dt_dev_pixelpipe_t *pipe)
257 {
258   dt_atomic_set_int(&pipe->shutdown,TRUE); // tell pipe that it should shut itself down if currently running
259 
260   // FIXME: either this or all process() -> gdk mutices have to be changed!
261   //        (this is a circular dependency on busy_mutex and the gdk mutex)
262   // [[does the above still apply?]]
263   dt_pthread_mutex_lock(&pipe->busy_mutex); // block until the pipe has shut down
264   // destroy all nodes
265   for(GList *nodes = pipe->nodes; nodes; nodes = g_list_next(nodes))
266   {
267     dt_dev_pixelpipe_iop_t *piece = (dt_dev_pixelpipe_iop_t *)nodes->data;
268     // printf("cleanup module `%s'\n", piece->module->name());
269     piece->module->cleanup_pipe(piece->module, pipe, piece);
270     free(piece->blendop_data);
271     piece->blendop_data = NULL;
272     free(piece->histogram);
273     piece->histogram = NULL;
274     g_hash_table_destroy(piece->raster_masks);
275     piece->raster_masks = NULL;
276     free(piece);
277   }
278   g_list_free(pipe->nodes);
279   pipe->nodes = NULL;
280   // also cleanup iop here
281   if(pipe->iop)
282   {
283     g_list_free(pipe->iop);
284     pipe->iop = NULL;
285   }
286   // and iop order
287   g_list_free_full(pipe->iop_order_list, free);
288   pipe->iop_order_list = NULL;
289   dt_pthread_mutex_unlock(&pipe->busy_mutex);	// safe for others to mess with the pipe now
290 }
291 
dt_dev_pixelpipe_rebuild(dt_develop_t * dev)292 void dt_dev_pixelpipe_rebuild(dt_develop_t *dev)
293 {
294   dev->pipe->changed |= DT_DEV_PIPE_REMOVE;
295   dev->preview_pipe->changed |= DT_DEV_PIPE_REMOVE;
296   dev->preview2_pipe->changed |= DT_DEV_PIPE_REMOVE;
297 
298   dev->pipe->cache_obsolete = 1;
299   dev->preview_pipe->cache_obsolete = 1;
300   dev->preview2_pipe->cache_obsolete = 1;
301 
302   // invalidate buffers and force redraw of darkroom
303   dt_dev_invalidate_all(dev);
304 }
305 
dt_dev_pixelpipe_create_nodes(dt_dev_pixelpipe_t * pipe,dt_develop_t * dev)306 void dt_dev_pixelpipe_create_nodes(dt_dev_pixelpipe_t *pipe, dt_develop_t *dev)
307 {
308   dt_pthread_mutex_lock(&pipe->busy_mutex); // block until pipe is idle
309   // clear any pending shutdown request
310   dt_atomic_set_int(&pipe->shutdown,FALSE);
311   // check that the pipe was actually properly cleaned up after the last run
312   g_assert(pipe->nodes == NULL);
313   g_assert(pipe->iop == NULL);
314   g_assert(pipe->iop_order_list == NULL);
315   pipe->iop_order_list = dt_ioppr_iop_order_copy_deep(dev->iop_order_list);
316   // for all modules in dev:
317   pipe->iop = g_list_copy(dev->iop);
318   for(GList *modules = pipe->iop; modules; modules = g_list_next(modules))
319   {
320     dt_iop_module_t *module = (dt_iop_module_t *)modules->data;
321     dt_dev_pixelpipe_iop_t *piece = (dt_dev_pixelpipe_iop_t *)calloc(1, sizeof(dt_dev_pixelpipe_iop_t));
322     piece->enabled = module->enabled;
323     piece->request_histogram = DT_REQUEST_ONLY_IN_GUI;
324     piece->histogram_params.roi = NULL;
325     piece->histogram_params.bins_count = 256;
326     piece->histogram_stats.bins_count = 0;
327     piece->histogram_stats.pixels = 0;
328     piece->colors
329         = ((module->default_colorspace(module, pipe, NULL) == iop_cs_RAW) && (dt_image_is_raw(&pipe->image)))
330               ? 1
331               : 4;
332     piece->iscale = pipe->iscale;
333     piece->iwidth = pipe->iwidth;
334     piece->iheight = pipe->iheight;
335     piece->module = module;
336     piece->pipe = pipe;
337     piece->data = NULL;
338     piece->hash = 0;
339     piece->process_cl_ready = 0;
340     piece->process_tiling_ready = 0;
341     piece->raster_masks = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, dt_free_align_ptr);
342     memset(&piece->processed_roi_in, 0, sizeof(piece->processed_roi_in));
343     memset(&piece->processed_roi_out, 0, sizeof(piece->processed_roi_out));
344     dt_iop_init_pipe(piece->module, pipe, piece);
345     pipe->nodes = g_list_append(pipe->nodes, piece);
346   }
347   dt_pthread_mutex_unlock(&pipe->busy_mutex); // safe for others to use/mess with the pipe now
348 }
349 
350 // helper
dt_dev_pixelpipe_synch(dt_dev_pixelpipe_t * pipe,dt_develop_t * dev,GList * history)351 void dt_dev_pixelpipe_synch(dt_dev_pixelpipe_t *pipe, dt_develop_t *dev, GList *history)
352 {
353   dt_dev_history_item_t *hist = (dt_dev_history_item_t *)history->data;
354   // find piece in nodes list
355   dt_dev_pixelpipe_iop_t *piece = NULL;
356 
357   const dt_image_t *img = &pipe->image;
358   const int32_t imgid = img->id;
359   const gboolean rawprep_img = dt_image_is_rawprepare_supported(img);
360   const gboolean raw_img     = dt_image_is_raw(img);
361 
362   pipe->want_detail_mask &= DT_DEV_DETAIL_MASK_REQUIRED;
363   if(raw_img)          pipe->want_detail_mask |= DT_DEV_DETAIL_MASK_DEMOSAIC;
364   else if(rawprep_img)
365     pipe->want_detail_mask |= DT_DEV_DETAIL_MASK_RAWPREPARE;
366 
367   for(GList *nodes = pipe->nodes; nodes; nodes = g_list_next(nodes))
368   {
369     piece = (dt_dev_pixelpipe_iop_t *)nodes->data;
370 
371     if(piece->module == hist->module)
372     {
373       const gboolean active = hist->enabled;
374       piece->enabled = active;
375 
376       // Styles, presets or history copy&paste might set history items not appropriate for the image.
377       // Fixing that seemed to be almost impossible after long discussions but at least we can test,
378       // correct and add a problem hint here.
379       if((strcmp(piece->module->op, "demosaic") == 0) || (strcmp(piece->module->op, "rawprepare") == 0))
380       {
381         if(rawprep_img && !active)
382           piece->enabled = TRUE;
383         else if(!rawprep_img && active)
384           piece->enabled = FALSE;
385       }
386       else if((strcmp(piece->module->op, "rawdenoise") == 0) ||
387               (strcmp(piece->module->op, "hotpixels") == 0) ||
388               (strcmp(piece->module->op, "cacorrect") == 0))
389       {
390         if(!rawprep_img && active) piece->enabled = FALSE;
391       }
392 
393       if(piece->enabled != hist->enabled)
394       {
395         if(piece->enabled)
396           dt_iop_set_module_trouble_message(piece->module, _("enabled as required"), _("history had module disabled but it is required for this type of image.\nlikely introduced by applying a preset, style or history copy&paste"), NULL);
397         else
398           dt_iop_set_module_trouble_message(piece->module, _("disabled as not appropriate"), _("history had module enabled but it is not allowed for this type of image.\nlikely introduced by applying a preset, style or history copy&paste"), NULL);
399         dt_print(DT_DEBUG_PARAMS, "[pixelpipe_synch] enabling mismatch for module %s in image %i\n", piece->module->op, imgid);
400       }
401       dt_iop_commit_params(hist->module, hist->params, hist->blend_params, pipe, piece);
402 
403       if(piece->blendop_data)
404       {
405         const dt_develop_blend_params_t *const bp = (const dt_develop_blend_params_t *)piece->blendop_data;
406         if(bp->details != 0.0f)
407           pipe->want_detail_mask |= DT_DEV_DETAIL_MASK_REQUIRED;
408       }
409     }
410   }
411 }
412 
dt_dev_pixelpipe_synch_all(dt_dev_pixelpipe_t * pipe,dt_develop_t * dev)413 void dt_dev_pixelpipe_synch_all(dt_dev_pixelpipe_t *pipe, dt_develop_t *dev)
414 {
415   dt_pthread_mutex_lock(&pipe->busy_mutex);
416 
417   dt_print(DT_DEBUG_PARAMS, "[pixelpipe] synch all modules with defaults_params for pipe %i\n", pipe->type);
418 
419   // call reset_params on all pieces first. This is mandatory to init utility modules that don't have an history stack
420   for(GList *nodes = pipe->nodes; nodes; nodes = g_list_next(nodes))
421   {
422     dt_dev_pixelpipe_iop_t *piece = (dt_dev_pixelpipe_iop_t *)nodes->data;
423     piece->hash = 0;
424     piece->enabled = piece->module->default_enabled;
425     dt_iop_commit_params(piece->module, piece->module->default_params, piece->module->default_blendop_params,
426                          pipe, piece);
427   }
428 
429   dt_print(DT_DEBUG_PARAMS, "[pixelpipe] synch all modules with history for pipe %i\n", pipe->type);
430 
431   // go through all history items and adjust params
432   GList *history = dev->history;
433   for(int k = 0; k < dev->history_end && history; k++)
434   {
435     dt_dev_pixelpipe_synch(pipe, dev, history);
436     history = g_list_next(history);
437   }
438   dt_pthread_mutex_unlock(&pipe->busy_mutex);
439 }
440 
dt_dev_pixelpipe_synch_top(dt_dev_pixelpipe_t * pipe,dt_develop_t * dev)441 void dt_dev_pixelpipe_synch_top(dt_dev_pixelpipe_t *pipe, dt_develop_t *dev)
442 {
443   dt_pthread_mutex_lock(&pipe->busy_mutex);
444   GList *history = g_list_nth(dev->history, dev->history_end - 1);
445   if(history)
446   {
447     dt_dev_history_item_t *hist = (dt_dev_history_item_t *)history->data;
448     dt_print(DT_DEBUG_PARAMS, "[pixelpipe] synch top history module `%s' for pipe %i\n", hist->module->op, pipe->type);
449     dt_dev_pixelpipe_synch(pipe, dev, history);
450   }
451   else
452   {
453     dt_print(DT_DEBUG_PARAMS, "[pixelpipe] synch top history module missing error for pipe %i\n", pipe->type);
454   }
455   dt_pthread_mutex_unlock(&pipe->busy_mutex);
456 }
457 
dt_dev_pixelpipe_change(dt_dev_pixelpipe_t * pipe,struct dt_develop_t * dev)458 void dt_dev_pixelpipe_change(dt_dev_pixelpipe_t *pipe, struct dt_develop_t *dev)
459 {
460   dt_pthread_mutex_lock(&dev->history_mutex);
461 
462   dt_print(DT_DEBUG_PARAMS, "[pixelpipe] pipeline state changing for pipe %i, flag %i\n", pipe->type, pipe->changed);
463   // case DT_DEV_PIPE_UNCHANGED: case DT_DEV_PIPE_ZOOMED:
464   if(pipe->changed & DT_DEV_PIPE_TOP_CHANGED)
465   {
466     // only top history item changed.
467     dt_dev_pixelpipe_synch_top(pipe, dev);
468   }
469   if(pipe->changed & DT_DEV_PIPE_SYNCH)
470   {
471     // pipeline topology remains intact, only change all params.
472     dt_dev_pixelpipe_synch_all(pipe, dev);
473   }
474   if(pipe->changed & DT_DEV_PIPE_REMOVE)
475   {
476     // modules have been added in between or removed. need to rebuild the whole pipeline.
477     dt_dev_pixelpipe_cleanup_nodes(pipe);
478     dt_dev_pixelpipe_create_nodes(pipe, dev);
479     dt_dev_pixelpipe_synch_all(pipe, dev);
480   }
481   pipe->changed = DT_DEV_PIPE_UNCHANGED;
482   dt_pthread_mutex_unlock(&dev->history_mutex);
483   dt_dev_pixelpipe_get_dimensions(pipe, dev, pipe->iwidth, pipe->iheight, &pipe->processed_width,
484                                   &pipe->processed_height);
485 }
486 
487 // TODO:
dt_dev_pixelpipe_add_node(dt_dev_pixelpipe_t * pipe,dt_develop_t * dev,int n)488 void dt_dev_pixelpipe_add_node(dt_dev_pixelpipe_t *pipe, dt_develop_t *dev, int n)
489 {
490 }
491 // TODO:
dt_dev_pixelpipe_remove_node(dt_dev_pixelpipe_t * pipe,dt_develop_t * dev,int n)492 void dt_dev_pixelpipe_remove_node(dt_dev_pixelpipe_t *pipe, dt_develop_t *dev, int n)
493 {
494 }
495 
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)496 static void get_output_format(dt_iop_module_t *module, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece,
497                               dt_develop_t *dev, dt_iop_buffer_dsc_t *dsc)
498 {
499   if(module) return module->output_format(module, pipe, piece, dsc);
500 
501   // first input.
502   *dsc = pipe->image.buf_dsc;
503 
504   if(!(dt_image_is_raw(&pipe->image)))
505   {
506     // image max is normalized before
507     for(int k = 0; k < 4; k++) dsc->processed_maximum[k] = 1.0f;
508   }
509 }
510 
511 
512 // helper to get per module histogram
histogram_collect(dt_dev_pixelpipe_iop_t * piece,const void * pixel,const dt_iop_roi_t * roi,uint32_t ** histogram,uint32_t * histogram_max)513 static void histogram_collect(dt_dev_pixelpipe_iop_t *piece, const void *pixel, const dt_iop_roi_t *roi,
514                               uint32_t **histogram, uint32_t *histogram_max)
515 {
516   dt_dev_histogram_collection_params_t histogram_params = piece->histogram_params;
517 
518   dt_histogram_roi_t histogram_roi;
519 
520   // if the current module does did not specified its own ROI, use the full ROI
521   if(histogram_params.roi == NULL)
522   {
523     histogram_roi = (dt_histogram_roi_t){
524       .width = roi->width, .height = roi->height, .crop_x = 0, .crop_y = 0, .crop_width = 0, .crop_height = 0
525     };
526 
527     histogram_params.roi = &histogram_roi;
528   }
529 
530   const dt_iop_colorspace_type_t cst = piece->module->input_colorspace(piece->module, piece->pipe, piece);
531 
532   dt_histogram_helper(&histogram_params, &piece->histogram_stats, cst, piece->module->histogram_cst, pixel, histogram,
533       piece->module->histogram_middle_grey, dt_ioppr_get_pipe_work_profile_info(piece->pipe));
534   dt_histogram_max_helper(&piece->histogram_stats, cst, piece->module->histogram_cst, histogram, histogram_max);
535 }
536 
537 #ifdef HAVE_OPENCL
538 // helper to get per module histogram for OpenCL
539 //
540 // this algorithm is inefficient as hell when it comes to larger images. it's only acceptable
541 // as long as we work on small image sizes like in image preview
histogram_collect_cl(int devid,dt_dev_pixelpipe_iop_t * piece,cl_mem img,const dt_iop_roi_t * roi,uint32_t ** histogram,uint32_t * histogram_max,float * buffer,size_t bufsize)542 static void histogram_collect_cl(int devid, dt_dev_pixelpipe_iop_t *piece, cl_mem img,
543                                  const dt_iop_roi_t *roi, uint32_t **histogram, uint32_t *histogram_max,
544                                  float *buffer, size_t bufsize)
545 {
546   float *tmpbuf = NULL;
547   float *pixel = NULL;
548 
549   // if buffer is supplied and if size fits let's use it
550   if(buffer && bufsize >= (size_t)roi->width * roi->height * 4 * sizeof(float))
551     pixel = buffer;
552   else
553     pixel = tmpbuf = dt_alloc_align_float((size_t)4 * roi->width * roi->height);
554 
555   if(!pixel) return;
556 
557   cl_int err = dt_opencl_copy_device_to_host(devid, pixel, img, roi->width, roi->height, sizeof(float) * 4);
558   if(err != CL_SUCCESS)
559   {
560     if(tmpbuf) dt_free_align(tmpbuf);
561     return;
562   }
563 
564   dt_dev_histogram_collection_params_t histogram_params = piece->histogram_params;
565 
566   dt_histogram_roi_t histogram_roi;
567 
568   // if the current module does did not specified its own ROI, use the full ROI
569   if(histogram_params.roi == NULL)
570   {
571     histogram_roi = (dt_histogram_roi_t){
572       .width = roi->width, .height = roi->height, .crop_x = 0, .crop_y = 0, .crop_width = 0, .crop_height = 0
573     };
574 
575     histogram_params.roi = &histogram_roi;
576   }
577 
578   const dt_iop_colorspace_type_t cst = piece->module->input_colorspace(piece->module, piece->pipe, piece);
579 
580   dt_histogram_helper(&histogram_params, &piece->histogram_stats, cst, piece->module->histogram_cst, pixel, histogram,
581       piece->module->histogram_middle_grey, dt_ioppr_get_pipe_work_profile_info(piece->pipe));
582   dt_histogram_max_helper(&piece->histogram_stats, cst, piece->module->histogram_cst, histogram, histogram_max);
583 
584   if(tmpbuf) dt_free_align(tmpbuf);
585 }
586 #endif
587 
588 // helper for per-module color picking
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)589 static int pixelpipe_picker_helper(dt_iop_module_t *module, const dt_iop_roi_t *roi, dt_aligned_pixel_t picked_color,
590                                    dt_aligned_pixel_t picked_color_min, dt_aligned_pixel_t picked_color_max,
591                                    dt_pixelpipe_picker_source_t picker_source, int *box)
592 {
593   const float wd = darktable.develop->preview_pipe->backbuf_width;
594   const float ht = darktable.develop->preview_pipe->backbuf_height;
595   const int width = roi->width;
596   const int height = roi->height;
597   const dt_image_t image = darktable.develop->image_storage;
598   const int op_after_demosaic = dt_ioppr_is_iop_before(darktable.develop->preview_pipe->iop_order_list,
599                                                        module->op, "demosaic", 0);
600   const dt_colorpicker_sample_t *const sample = darktable.lib->proxy.colorpicker.primary_sample;
601 
602   dt_boundingbox_t fbox = { 0.0f };
603 
604   // get absolute pixel coordinates in final preview image
605   if(sample->size == DT_LIB_COLORPICKER_SIZE_BOX)
606   {
607     for(int k = 0; k < 4; k += 2) fbox[k] = sample->box[k] * wd;
608     for(int k = 1; k < 4; k += 2) fbox[k] = sample->box[k] * ht;
609   }
610   else if(sample->size == DT_LIB_COLORPICKER_SIZE_POINT)
611   {
612     fbox[0] = fbox[2] = sample->point[0] * wd;
613     fbox[1] = fbox[3] = sample->point[1] * ht;
614   }
615 
616   // transform back to current module coordinates
617   dt_dev_distort_backtransform_plus(darktable.develop, darktable.develop->preview_pipe, module->iop_order,
618                                ((picker_source == PIXELPIPE_PICKER_INPUT) ? DT_DEV_TRANSFORM_DIR_FORW_INCL
619                                : DT_DEV_TRANSFORM_DIR_FORW_EXCL),fbox, 2);
620 
621   if (op_after_demosaic || !dt_image_is_rawprepare_supported(&image))
622     for(int idx = 0; idx < 4; idx++) fbox[idx] *= darktable.develop->preview_downsampling;
623   fbox[0] -= roi->x;
624   fbox[1] -= roi->y;
625   fbox[2] -= roi->x;
626   fbox[3] -= roi->y;
627 
628   // re-order edges of bounding box
629   box[0] = fminf(fbox[0], fbox[2]);
630   box[1] = fminf(fbox[1], fbox[3]);
631   box[2] = fmaxf(fbox[0], fbox[2]);
632   box[3] = fmaxf(fbox[1], fbox[3]);
633 
634   if(sample->size == DT_LIB_COLORPICKER_SIZE_POINT)
635   {
636     // if we are sampling one point, make sure that we actually sample it.
637     for(int k = 2; k < 4; k++) box[k] += 1;
638   }
639 
640   // do not continue if box is completely outside of roi
641   if(box[0] >= width || box[1] >= height || box[2] < 0 || box[3] < 0) return 1;
642 
643   // clamp bounding box to roi
644   for(int k = 0; k < 4; k += 2) box[k] = MIN(width - 1, MAX(0, box[k]));
645   for(int k = 1; k < 4; k += 2) box[k] = MIN(height - 1, MAX(0, box[k]));
646 
647   // safety check: area needs to have minimum 1 pixel width and height
648   if(box[2] - box[0] < 1 || box[3] - box[1] < 1) return 1;
649 
650   return 0;
651 }
652 
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)653 static void pixelpipe_picker(dt_iop_module_t *module, dt_dev_pixelpipe_iop_t *piece, dt_iop_buffer_dsc_t *dsc,
654                              const float *pixel, const dt_iop_roi_t *roi, float *picked_color,
655                              float *picked_color_min, float *picked_color_max,
656                              const dt_iop_colorspace_type_t image_cst, dt_pixelpipe_picker_source_t picker_source)
657 {
658   int box[4] = { 0 };
659 
660   if(pixelpipe_picker_helper(module, roi, picked_color, picked_color_min, picked_color_max, picker_source, box))
661   {
662     for(int k = 0; k < 4; k++)
663     {
664       picked_color_min[k] = INFINITY;
665       picked_color_max[k] = -INFINITY;
666       picked_color[k] = 0.0f;
667     }
668 
669     return;
670   }
671 
672   dt_aligned_pixel_t min, max, avg;
673   for(int k = 0; k < 4; k++)
674   {
675     min[k] = INFINITY;
676     max[k] = -INFINITY;
677     avg[k] = 0.0f;
678   }
679 
680   const dt_iop_order_iccprofile_info_t *const profile = dt_ioppr_get_pipe_current_profile_info(module, piece->pipe);
681   dt_color_picker_helper(dsc, pixel, roi, box, avg, min, max, image_cst,
682                          dt_iop_color_picker_get_active_cst(module), profile);
683 
684   for(int k = 0; k < 4; k++)
685   {
686     picked_color_min[k] = min[k];
687     picked_color_max[k] = max[k];
688     picked_color[k] = avg[k];
689   }
690 }
691 
692 
693 #ifdef HAVE_OPENCL
694 // helper for OpenCL color picking
695 //
696 // this algorithm is inefficient as hell when it comes to larger images. it's only acceptable
697 // as long as we work on small image sizes like in image preview
pixelpipe_picker_cl(int devid,dt_iop_module_t * module,dt_dev_pixelpipe_iop_t * piece,dt_iop_buffer_dsc_t * dsc,cl_mem img,const dt_iop_roi_t * roi,float * picked_color,float * picked_color_min,float * picked_color_max,float * buffer,size_t bufsize,const dt_iop_colorspace_type_t image_cst,dt_pixelpipe_picker_source_t picker_source)698 static void pixelpipe_picker_cl(int devid, dt_iop_module_t *module, dt_dev_pixelpipe_iop_t *piece,
699                                 dt_iop_buffer_dsc_t *dsc, cl_mem img, const dt_iop_roi_t *roi,
700                                 float *picked_color, float *picked_color_min, float *picked_color_max,
701                                 float *buffer, size_t bufsize, const dt_iop_colorspace_type_t image_cst,
702                                 dt_pixelpipe_picker_source_t picker_source)
703 {
704   int box[4] = { 0 };
705 
706   if(pixelpipe_picker_helper(module, roi, picked_color, picked_color_min, picked_color_max, picker_source, box))
707   {
708     for(int k = 0; k < 4; k++)
709     {
710       picked_color_min[k] = INFINITY;
711       picked_color_max[k] = -INFINITY;
712       picked_color[k] = 0.0f;
713     }
714 
715     return;
716   }
717 
718   const size_t origin[3] = { box[0], box[1], 0 };
719   const size_t region[3] = { box[2] - box[0], box[3] - box[1], 1 };
720 
721   float *pixel = NULL;
722   float *tmpbuf = NULL;
723 
724   const size_t size = region[0] * region[1];
725 
726   const size_t bpp = dt_iop_buffer_dsc_to_bpp(dsc);
727 
728   // if a buffer is supplied and if size fits let's use it
729   if(buffer && bufsize >= size * bpp)
730     pixel = buffer;
731   else
732     pixel = tmpbuf = dt_alloc_align(64, size * bpp);
733 
734   if(pixel == NULL) return;
735 
736   // get the required part of the image from opencl device
737   cl_int err = dt_opencl_read_host_from_device_raw(devid, pixel, img, origin, region, region[0] * bpp, CL_TRUE);
738 
739   if(err != CL_SUCCESS) goto error;
740 
741   dt_iop_roi_t roi_copy = (dt_iop_roi_t){.x = roi->x + box[0], .y = roi->y + box[1], .width = region[0], .height = region[1] };
742 
743   box[0] = 0;
744   box[1] = 0;
745   box[2] = region[0];
746   box[3] = region[1];
747 
748   dt_aligned_pixel_t min, max, avg;
749   for(int k = 0; k < 4; k++)
750   {
751     min[k] = INFINITY;
752     max[k] = -INFINITY;
753     avg[k] = 0.0f;
754   }
755 
756   const dt_iop_order_iccprofile_info_t *const profile = dt_ioppr_get_pipe_current_profile_info(module, piece->pipe);
757   dt_color_picker_helper(dsc, pixel, &roi_copy, box, avg, min, max, image_cst,
758                          dt_iop_color_picker_get_active_cst(module), profile);
759 
760   for(int k = 0; k < 4; k++)
761   {
762     picked_color_min[k] = min[k];
763     picked_color_max[k] = max[k];
764     picked_color[k] = avg[k];
765   }
766 
767 error:
768   dt_free_align(tmpbuf);
769 }
770 #endif
771 
_pixelpipe_pick_from_image(dt_iop_module_t * module,const float * const pixel,const dt_iop_roi_t * roi_in,const dt_iop_order_iccprofile_info_t * const display_profile,const dt_iop_order_iccprofile_info_t * const histogram_profile,dt_colorpicker_sample_t * const sample)772 static void _pixelpipe_pick_from_image(dt_iop_module_t *module,
773                                        const float *const pixel, const dt_iop_roi_t *roi_in,
774                                        const dt_iop_order_iccprofile_info_t *const display_profile,
775                                        const dt_iop_order_iccprofile_info_t *const histogram_profile,
776                                        dt_colorpicker_sample_t *const sample)
777 {
778   if(sample->size == DT_LIB_COLORPICKER_SIZE_BOX)
779   {
780     const int box[4] = {
781       MIN(roi_in->width - 1,  MAX(0, sample->box[0] * roi_in->width)),
782       MIN(roi_in->height - 1, MAX(0, sample->box[1] * roi_in->height)),
783       MIN(roi_in->width - 1,  MAX(0, sample->box[2] * roi_in->width)),
784       MIN(roi_in->height - 1, MAX(0, sample->box[3] * roi_in->height))
785     };
786     const int box_pixels = (box[3] - box[1] + 1) * (box[2] - box[0] + 1);
787     lib_colorpicker_sample_statistics picked_rgb = { { 0.0f },
788                                                      { FLT_MAX, FLT_MAX, FLT_MAX },
789                                                      { FLT_MIN, FLT_MIN, FLT_MIN } };
790     dt_aligned_pixel_t acc = { 0.0f };
791 
792     for(int j = box[1]; j <= box[3]; j++)
793       for(int i = box[0]; i <= box[2]; i++)
794       {
795         for_each_channel(ch, aligned(picked_rgb, acc) aligned(pixel:64))
796         {
797           const float v = pixel[4 * (roi_in->width * j + i) + ch];
798           picked_rgb[DT_LIB_COLORPICKER_STATISTIC_MIN][ch]
799               = MIN(picked_rgb[DT_LIB_COLORPICKER_STATISTIC_MIN][ch], v);
800           picked_rgb[DT_LIB_COLORPICKER_STATISTIC_MAX][ch]
801               = MAX(picked_rgb[DT_LIB_COLORPICKER_STATISTIC_MAX][ch], v);
802           acc[ch] += v;
803         }
804       }
805     for_each_channel(ch, aligned(picked_rgb, acc:16))
806       picked_rgb[DT_LIB_COLORPICKER_STATISTIC_MEAN][ch] = acc[ch] / box_pixels;
807 
808     // convenient to have pixels in display profile, which makes them easy to display
809     memcpy(sample->display[0], picked_rgb[0], sizeof(lib_colorpicker_sample_statistics));
810 
811     // NOTE: conversions assume that dt_aligned_pixel_t[x] has no
812     // padding, e.g. is equivalent to float[x*4], and that on failure
813     // it's OK not to touch output
814     int converted_cst;
815     dt_ioppr_transform_image_colorspace(module, picked_rgb[0], sample->lab[0], 3, 1, iop_cs_rgb, iop_cs_Lab,
816                                         &converted_cst, display_profile);
817     if(display_profile && histogram_profile)
818       dt_ioppr_transform_image_colorspace_rgb(picked_rgb[0], sample->scope[0], 3, 1,
819                                               display_profile, histogram_profile, "primary picker");
820   }
821   else if(sample->size == DT_LIB_COLORPICKER_SIZE_POINT)
822   {
823     const int x = MIN(roi_in->width - 1, MAX(0, sample->point[0] * roi_in->width));
824     const int y = MIN(roi_in->height - 1, MAX(0, sample->point[1] * roi_in->height));
825     int converted_cst;
826     // mean = min = max == pixel sample, so only need to do colorspace work on a single point
827     memcpy(sample->display[0], pixel + 4 * (roi_in->width * y + x), sizeof(dt_aligned_pixel_t));
828     dt_ioppr_transform_image_colorspace(module, sample->display[0], sample->lab[0], 1, 1, iop_cs_rgb, iop_cs_Lab,
829                                         &converted_cst, display_profile);
830     if(display_profile && histogram_profile)
831       dt_ioppr_transform_image_colorspace_rgb(sample->display[0], sample->scope[0], 1, 1,
832                                               display_profile, histogram_profile, "primary picker");
833     for(dt_lib_colorpicker_statistic_t stat = 1; stat < DT_LIB_COLORPICKER_STATISTIC_N; stat++)
834     {
835       memcpy(sample->display[stat], sample->display[0], sizeof(dt_aligned_pixel_t));
836       memcpy(sample->lab[stat], sample->lab[0], sizeof(dt_aligned_pixel_t));
837       memcpy(sample->scope[stat], sample->scope[0], sizeof(dt_aligned_pixel_t));
838     }
839   }
840 }
841 
_pixelpipe_pick_samples(dt_develop_t * dev,dt_iop_module_t * module,const float * const input,const dt_iop_roi_t * roi_in)842 static void _pixelpipe_pick_samples(dt_develop_t *dev, dt_iop_module_t *module,
843                                     const float *const input, const dt_iop_roi_t *roi_in)
844 {
845   const dt_iop_order_iccprofile_info_t *const histogram_profile = dt_ioppr_get_histogram_profile_info(dev);
846   const dt_iop_order_iccprofile_info_t *const display_profile
847     = dt_ioppr_add_profile_info_to_list(dev, darktable.color_profiles->display_type,
848                                         darktable.color_profiles->display_filename, INTENT_RELATIVE_COLORIMETRIC);
849 
850   GSList *samples = darktable.lib->proxy.colorpicker.live_samples;
851   while(samples)
852   {
853     dt_colorpicker_sample_t *sample = samples->data;
854     if(!sample->locked)
855       _pixelpipe_pick_from_image(module, input, roi_in, display_profile, histogram_profile, sample);
856     samples = g_slist_next(samples);
857   }
858 
859   if(darktable.lib->proxy.colorpicker.picker_proxy)
860     _pixelpipe_pick_from_image(module, input, roi_in, display_profile, histogram_profile,
861                                darktable.lib->proxy.colorpicker.primary_sample);
862 }
863 
864 // returns 1 if blend process need the module default colorspace
_transform_for_blend(const dt_iop_module_t * const self,const dt_dev_pixelpipe_iop_t * const piece)865 static gboolean _transform_for_blend(const dt_iop_module_t *const self, const dt_dev_pixelpipe_iop_t *const piece)
866 {
867   const dt_develop_blend_params_t *const d = (const dt_develop_blend_params_t *)piece->blendop_data;
868   if(d)
869   {
870     // check only if blend is active
871     if((self->flags() & IOP_FLAGS_SUPPORTS_BLENDING) && (d->mask_mode != DEVELOP_MASK_DISABLED))
872     {
873       return TRUE;
874     }
875   }
876   return FALSE;
877 }
878 
_transform_for_picker(dt_iop_module_t * self,const dt_iop_colorspace_type_t cst)879 static dt_iop_colorspace_type_t _transform_for_picker(dt_iop_module_t *self, const dt_iop_colorspace_type_t cst)
880 {
881   const dt_iop_colorspace_type_t picker_cst =
882     dt_iop_color_picker_get_active_cst(self);
883 
884   switch(picker_cst)
885   {
886     case iop_cs_RAW:
887       return iop_cs_RAW;
888     case iop_cs_Lab:
889     case iop_cs_LCh:
890       return iop_cs_Lab;
891     case iop_cs_rgb:
892     case iop_cs_HSL:
893     case iop_cs_JzCzhz:
894       return iop_cs_rgb;
895     case iop_cs_NONE:
896       // iop_cs_NONE is used by temperature.c as it may work in RAW or RGB
897       // return the pipe color space to avoid any additional conversions
898       return cst;
899     default:
900       return picker_cst;
901   }
902 }
903 
_request_color_pick(dt_dev_pixelpipe_t * pipe,dt_develop_t * dev,dt_iop_module_t * module)904 static gboolean _request_color_pick(dt_dev_pixelpipe_t *pipe, dt_develop_t *dev, dt_iop_module_t *module)
905 {
906   // Does the current active module need a picker?
907   return
908     // pick from preview pipe to get pixels outside the viewport
909     dev->gui_attached && pipe == dev->preview_pipe
910     // there is an active picker widget
911     && darktable.lib->proxy.colorpicker.picker_proxy
912     // only modules with focus can pick
913     && module == dev->gui_module
914     // and they are enabled
915     && dev->gui_module->enabled
916     // and they want to pick ;)
917     && module->request_color_pick != DT_REQUEST_COLORPICK_OFF;
918 }
919 
collect_histogram_on_CPU(dt_dev_pixelpipe_t * pipe,dt_develop_t * dev,float * input,const dt_iop_roi_t * roi_in,dt_iop_module_t * module,dt_dev_pixelpipe_iop_t * piece,dt_pixelpipe_flow_t * pixelpipe_flow)920 static void collect_histogram_on_CPU(dt_dev_pixelpipe_t *pipe, dt_develop_t *dev,
921                                      float *input, const dt_iop_roi_t *roi_in,
922                                      dt_iop_module_t *module, dt_dev_pixelpipe_iop_t *piece,
923                                      dt_pixelpipe_flow_t *pixelpipe_flow)
924 {
925   // histogram collection for module
926   if((dev->gui_attached || !(piece->request_histogram & DT_REQUEST_ONLY_IN_GUI))
927      && (piece->request_histogram & DT_REQUEST_ON))
928   {
929     histogram_collect(piece, input, roi_in, &(piece->histogram), piece->histogram_max);
930     *pixelpipe_flow |= (PIXELPIPE_FLOW_HISTOGRAM_ON_CPU);
931     *pixelpipe_flow &= ~(PIXELPIPE_FLOW_HISTOGRAM_NONE | PIXELPIPE_FLOW_HISTOGRAM_ON_GPU);
932 
933     if(piece->histogram && (module->request_histogram & DT_REQUEST_ON)
934        && (pipe->type & DT_DEV_PIXELPIPE_PREVIEW) == DT_DEV_PIXELPIPE_PREVIEW)
935     {
936       const size_t buf_size = 4 * piece->histogram_stats.bins_count * sizeof(uint32_t);
937       module->histogram = realloc(module->histogram, buf_size);
938       memcpy(module->histogram, piece->histogram, buf_size);
939       module->histogram_stats = piece->histogram_stats;
940       memcpy(module->histogram_max, piece->histogram_max, sizeof(piece->histogram_max));
941       if(module->widget)
942         dt_control_queue_redraw_widget(module->widget);
943     }
944   }
945   return;
946 }
947 
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)948 static int pixelpipe_process_on_CPU(dt_dev_pixelpipe_t *pipe, dt_develop_t *dev,
949                                     float *input, dt_iop_buffer_dsc_t *input_format, const dt_iop_roi_t *roi_in,
950                                     void **output, dt_iop_buffer_dsc_t **out_format, const dt_iop_roi_t *roi_out,
951                                     dt_iop_module_t *module, dt_dev_pixelpipe_iop_t *piece,
952                                     dt_develop_tiling_t *tiling, dt_pixelpipe_flow_t *pixelpipe_flow)
953 {
954   if(dt_atomic_get_int(&pipe->shutdown))
955     return 1;
956 
957   // Fetch RGB working profile
958   // if input is RAW, we can't color convert because RAW is not in a color space
959   // so we send NULL to by-pass
960   const dt_iop_order_iccprofile_info_t *const work_profile
961       = (input_format->cst != iop_cs_RAW) ? dt_ioppr_get_pipe_work_profile_info(pipe) : NULL;
962 
963   // transform to module input colorspace
964   dt_ioppr_transform_image_colorspace(module, input, input, roi_in->width, roi_in->height, input_format->cst,
965                                       module->input_colorspace(module, pipe, piece), &input_format->cst,
966                                       work_profile);
967 
968   //fprintf(stdout, "input color space for %s : %i\n", module->op, module->input_colorspace(module, pipe, piece));
969 
970   if(dt_atomic_get_int(&pipe->shutdown))
971     return 1;
972 
973   collect_histogram_on_CPU(pipe, dev, input, roi_in, module, piece, pixelpipe_flow);
974 
975   if(dt_atomic_get_int(&pipe->shutdown))
976     return 1;
977 
978   const size_t in_bpp = dt_iop_buffer_dsc_to_bpp(input_format);
979   const size_t bpp = dt_iop_buffer_dsc_to_bpp(*out_format);
980 
981   const gboolean needs_tiling = (piece->process_tiling_ready &&
982      !dt_tiling_piece_fits_host_memory(MAX(roi_in->width, roi_out->width),
983                                        MAX(roi_in->height, roi_out->height), MAX(in_bpp, bpp),
984                                           tiling->factor, tiling->overhead));
985 
986   /* process module on cpu. use tiling if needed and possible. */
987   if(needs_tiling || (darktable.unmuted & DT_DEBUG_TILING))
988   {
989     module->process_tiling(module, piece, input, *output, roi_in, roi_out, in_bpp);
990     *pixelpipe_flow |= (PIXELPIPE_FLOW_PROCESSED_ON_CPU | PIXELPIPE_FLOW_PROCESSED_WITH_TILING);
991     *pixelpipe_flow &= ~(PIXELPIPE_FLOW_PROCESSED_ON_GPU);
992   }
993   else
994   {
995     module->process(module, piece, input, *output, roi_in, roi_out);
996     *pixelpipe_flow |= (PIXELPIPE_FLOW_PROCESSED_ON_CPU);
997     *pixelpipe_flow &= ~(PIXELPIPE_FLOW_PROCESSED_ON_GPU | PIXELPIPE_FLOW_PROCESSED_WITH_TILING);
998   }
999 
1000   // and save the output colorspace
1001   pipe->dsc.cst = module->output_colorspace(module, pipe, piece);
1002 
1003   if(dt_atomic_get_int(&pipe->shutdown))
1004   {
1005     return 1;
1006   }
1007 
1008   // Lab color picking for module
1009   if(_request_color_pick(pipe, dev, module))
1010   {
1011     // ensure that we are using the right color space
1012     dt_iop_colorspace_type_t picker_cst = _transform_for_picker(module, pipe->dsc.cst);
1013     dt_ioppr_transform_image_colorspace(module, input, input, roi_in->width, roi_in->height,
1014                                         input_format->cst, picker_cst, &input_format->cst,
1015                                         work_profile);
1016     dt_ioppr_transform_image_colorspace(module, *output, *output, roi_out->width, roi_out->height,
1017                                         pipe->dsc.cst, picker_cst, &pipe->dsc.cst,
1018                                         work_profile);
1019 
1020     pixelpipe_picker(module, piece, &piece->dsc_in, (float *)input, roi_in, module->picked_color,
1021                      module->picked_color_min, module->picked_color_max, input_format->cst, PIXELPIPE_PICKER_INPUT);
1022     pixelpipe_picker(module, piece, &pipe->dsc, (float *)(*output), roi_out, module->picked_output_color,
1023                      module->picked_output_color_min, module->picked_output_color_max,
1024                      pipe->dsc.cst, PIXELPIPE_PICKER_OUTPUT);
1025 
1026     DT_DEBUG_CONTROL_SIGNAL_RAISE(darktable.signals, DT_SIGNAL_CONTROL_PICKERDATA_READY, module, piece);
1027   }
1028 
1029   if(dt_atomic_get_int(&pipe->shutdown))
1030   {
1031     return 1;
1032   }
1033 
1034   // blend needs input/output images with default colorspace
1035   if(_transform_for_blend(module, piece))
1036   {
1037     dt_iop_colorspace_type_t blend_cst = dt_develop_blend_colorspace(piece, pipe->dsc.cst);
1038     dt_ioppr_transform_image_colorspace(module, input, input, roi_in->width, roi_in->height,
1039                                         input_format->cst, blend_cst, &input_format->cst,
1040                                         work_profile);
1041     dt_ioppr_transform_image_colorspace(module, *output, *output, roi_out->width, roi_out->height,
1042                                         pipe->dsc.cst, blend_cst, &pipe->dsc.cst,
1043                                         work_profile);
1044   }
1045 
1046   if(dt_atomic_get_int(&pipe->shutdown))
1047     return 1;
1048 
1049   /* process blending on CPU */
1050   dt_develop_blend_process(module, piece, input, *output, roi_in, roi_out);
1051   *pixelpipe_flow |= (PIXELPIPE_FLOW_BLENDED_ON_CPU);
1052   *pixelpipe_flow &= ~(PIXELPIPE_FLOW_BLENDED_ON_GPU);
1053 
1054   if(dt_atomic_get_int(&pipe->shutdown))
1055   {
1056     return 1;
1057   }
1058   return 0; //no errors
1059 }
1060 
1061 // recursive helper for process:
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,const dt_iop_roi_t * roi_out,GList * modules,GList * pieces,int pos)1062 static int dt_dev_pixelpipe_process_rec(dt_dev_pixelpipe_t *pipe, dt_develop_t *dev, void **output,
1063                                         void **cl_mem_output, dt_iop_buffer_dsc_t **out_format,
1064                                         const dt_iop_roi_t *roi_out, GList *modules, GList *pieces, int pos)
1065 {
1066   if (dt_atomic_get_int(&pipe->shutdown))
1067     return 1;
1068 
1069   dt_iop_roi_t roi_in = *roi_out;
1070 
1071   char module_name[256] = { 0 };
1072   void *input = NULL;
1073   void *cl_mem_input = NULL;
1074   *cl_mem_output = NULL;
1075   dt_iop_module_t *module = NULL;
1076   dt_dev_pixelpipe_iop_t *piece = NULL;
1077 
1078   // if a module is active, check if this module allow a fast pipe run
1079 
1080   if(darktable.develop && dev->gui_module && dev->gui_module->flags() & IOP_FLAGS_ALLOW_FAST_PIPE)
1081     pipe->type |= DT_DEV_PIXELPIPE_FAST;
1082   else
1083     pipe->type &= ~DT_DEV_PIXELPIPE_FAST;
1084 
1085   if(modules)
1086   {
1087     module = (dt_iop_module_t *)modules->data;
1088     piece = (dt_dev_pixelpipe_iop_t *)pieces->data;
1089     // skip this module?
1090     if(!piece->enabled
1091        || (dev->gui_module && dev->gui_module != module
1092            && dev->gui_module->operation_tags_filter() & module->operation_tags()))
1093       return dt_dev_pixelpipe_process_rec(pipe, dev, output, cl_mem_output, out_format, &roi_in,
1094                                           g_list_previous(modules), g_list_previous(pieces), pos - 1);
1095   }
1096 
1097   if(module) g_strlcpy(module_name, module->op, MIN(sizeof(module_name), sizeof(module->op)));
1098   get_output_format(module, pipe, piece, dev, *out_format);
1099   const size_t bpp = dt_iop_buffer_dsc_to_bpp(*out_format);
1100   const size_t bufsize = (size_t)bpp * roi_out->width * roi_out->height;
1101 
1102   // 1) if cached buffer is still available, return data
1103   if(dt_atomic_get_int(&pipe->shutdown))
1104   {
1105     return 1;
1106   }
1107   gboolean cache_available = FALSE;
1108   uint64_t basichash = 0;
1109   uint64_t hash = 0;
1110   // do not get gamma from cache on preview pipe so we can compute the final histogram
1111   if((pipe->type & DT_DEV_PIXELPIPE_PREVIEW) != DT_DEV_PIXELPIPE_PREVIEW
1112      || module == NULL
1113      || strcmp(module->op, "gamma") != 0)
1114   {
1115     dt_dev_pixelpipe_cache_fullhash(pipe->image.id, roi_out, pipe, pos, &basichash, &hash);
1116     cache_available = dt_dev_pixelpipe_cache_available(&(pipe->cache), hash);
1117   }
1118   if(cache_available)
1119   {
1120     dt_print(DT_DEBUG_PARAMS, "[pixelpipe] dt_dev_pixelpipe_process_rec, cache available for pipe %i with hash %lu\n", pipe->type, (long unsigned int)hash);
1121     // if(module) printf("found valid buf pos %d in cache for module %s %s %lu\n", pos, module->op, pipe ==
1122     // dev->preview_pipe ? "[preview]" : "", hash);
1123 
1124     (void)dt_dev_pixelpipe_cache_get(&(pipe->cache), basichash, hash, bufsize, output, out_format);
1125 
1126     if(!modules) return 0;
1127     // go to post-collect directly:
1128     goto post_process_collect_info;
1129   }
1130 
1131   // 2) if history changed or exit event, abort processing?
1132   // preview pipe: abort on all but zoom events (same buffer anyways)
1133   if(dt_iop_breakpoint(dev, pipe)) return 1;
1134   // if image has changed, stop now.
1135   if(pipe == dev->pipe && dev->image_force_reload) return 1;
1136   if(pipe == dev->preview_pipe && dev->preview_loading) return 1;
1137   if(pipe == dev->preview2_pipe && dev->preview2_loading) return 1;
1138   if(dev->gui_leaving) return 1;
1139 
1140 
1141   // 3) input -> output
1142   if(!modules)
1143   {
1144     // 3a) import input array with given scale and roi
1145     if(dt_atomic_get_int(&pipe->shutdown))
1146     {
1147       return 1;
1148     }
1149     dt_times_t start;
1150     dt_get_times(&start);
1151     // we're looking for the full buffer
1152     {
1153       if(roi_out->scale == 1.0 && roi_out->x == 0 && roi_out->y == 0 && pipe->iwidth == roi_out->width
1154          && pipe->iheight == roi_out->height)
1155       {
1156         *output = pipe->input;
1157       }
1158       else if(dt_dev_pixelpipe_cache_get(&(pipe->cache), basichash, hash, bufsize, output, out_format))
1159       {
1160         if(roi_in.scale == 1.0f)
1161         {
1162           // fast branch for 1:1 pixel copies.
1163 
1164           // last minute clamping to catch potential out-of-bounds in roi_in and roi_out
1165 
1166           const int in_x = MAX(roi_in.x, 0);
1167           const int in_y = MAX(roi_in.y, 0);
1168           const int cp_width = MAX(0, MIN(roi_out->width, pipe->iwidth - in_x));
1169           const int cp_height = MIN(roi_out->height, pipe->iheight - in_y);
1170 
1171           if (cp_width > 0)
1172           {
1173 #ifdef _OPENMP
1174 #pragma omp parallel for default(none) \
1175           dt_omp_firstprivate(bpp, cp_height, cp_width, in_x, in_y) \
1176           shared(pipe, roi_out, roi_in, output) \
1177           schedule(static)
1178 #endif
1179             for(int j = 0; j < cp_height; j++)
1180               memcpy(((char *)*output) + (size_t)bpp * j * roi_out->width,
1181                      ((char *)pipe->input) + (size_t)bpp * (in_x + (in_y + j) * pipe->iwidth),
1182                      (size_t)bpp * cp_width);
1183           }
1184         }
1185         else
1186         {
1187           roi_in.x /= roi_out->scale;
1188           roi_in.y /= roi_out->scale;
1189           roi_in.width = pipe->iwidth;
1190           roi_in.height = pipe->iheight;
1191           roi_in.scale = 1.0f;
1192           dt_iop_clip_and_zoom(*output, pipe->input, roi_out, &roi_in, roi_out->width, pipe->iwidth);
1193         }
1194       }
1195       // else found in cache.
1196     }
1197 
1198     dt_show_times_f(&start, "[dev_pixelpipe]", "initing base buffer [%s]", _pipe_type_to_str(pipe->type));
1199   }
1200   else
1201   {
1202     // 3b) recurse and obtain output array in &input
1203 
1204     // get region of interest which is needed in input
1205     if(dt_atomic_get_int(&pipe->shutdown))
1206     {
1207       return 1;
1208     }
1209     module->modify_roi_in(module, piece, roi_out, &roi_in);
1210 
1211     // recurse to get actual data of input buffer
1212 
1213     dt_iop_buffer_dsc_t _input_format = { 0 };
1214     dt_iop_buffer_dsc_t *input_format = &_input_format;
1215 
1216     piece = (dt_dev_pixelpipe_iop_t *)pieces->data;
1217 
1218     piece->processed_roi_in = roi_in;
1219     piece->processed_roi_out = *roi_out;
1220 
1221     if(dt_dev_pixelpipe_process_rec(pipe, dev, &input, &cl_mem_input, &input_format, &roi_in,
1222                                     g_list_previous(modules), g_list_previous(pieces), pos - 1))
1223       return 1;
1224 
1225     const size_t in_bpp = dt_iop_buffer_dsc_to_bpp(input_format);
1226 
1227     piece->dsc_out = piece->dsc_in = *input_format;
1228 
1229     module->output_format(module, pipe, piece, &piece->dsc_out);
1230 
1231     **out_format = pipe->dsc = piece->dsc_out;
1232 
1233     const size_t out_bpp = dt_iop_buffer_dsc_to_bpp(*out_format);
1234 
1235     // reserve new cache line: output
1236     if(dt_atomic_get_int(&pipe->shutdown))
1237     {
1238       return 1;
1239     }
1240 
1241     gboolean important = FALSE;
1242     if((pipe->type & DT_DEV_PIXELPIPE_PREVIEW) == DT_DEV_PIXELPIPE_PREVIEW)
1243       important = (strcmp(module->op, "colorout") == 0);
1244     else
1245       important = (strcmp(module->op, "gamma") == 0);
1246     if(important)
1247       (void)dt_dev_pixelpipe_cache_get_important(&(pipe->cache), basichash, hash, bufsize, output, out_format);
1248     else
1249       (void)dt_dev_pixelpipe_cache_get(&(pipe->cache), basichash, hash, bufsize, output, out_format);
1250 
1251 // if(module) printf("reserving new buf in cache for module %s %s: %ld buf %p\n", module->op, pipe ==
1252 // dev->preview_pipe ? "[preview]" : "", hash, *output);
1253 
1254     if(dt_atomic_get_int(&pipe->shutdown))
1255     {
1256       return 1;
1257     }
1258 
1259     dt_times_t start;
1260     dt_get_times(&start);
1261 
1262     dt_pixelpipe_flow_t pixelpipe_flow = (PIXELPIPE_FLOW_NONE | PIXELPIPE_FLOW_HISTOGRAM_NONE);
1263 
1264     // special case: user requests to see channel data in the parametric mask of a module, or the blending
1265     // mask. In that case we skip all modules manipulating pixel content and only process image distorting
1266     // modules. Finally "gamma" is responsible for displaying channel/mask data accordingly.
1267     if(strcmp(module->op, "gamma") != 0
1268        && (pipe->mask_display & (DT_DEV_PIXELPIPE_DISPLAY_ANY | DT_DEV_PIXELPIPE_DISPLAY_MASK))
1269        && !(module->operation_tags() & IOP_TAG_DISTORT)
1270        && (in_bpp == out_bpp) && !memcmp(&roi_in, roi_out, sizeof(struct dt_iop_roi_t)))
1271     {
1272       // since we're not actually running the module, the output format is the same as the input format
1273       **out_format = pipe->dsc = piece->dsc_out = piece->dsc_in;
1274 
1275 #ifdef HAVE_OPENCL
1276       if(dt_opencl_is_inited() && pipe->opencl_enabled && pipe->devid >= 0 && (cl_mem_input != NULL))
1277       {
1278         *cl_mem_output = cl_mem_input;
1279       }
1280       else
1281       {
1282 #ifdef _OPENMP
1283 #pragma omp parallel for default(none) \
1284         dt_omp_firstprivate(in_bpp, out_bpp) \
1285         shared(roi_out, roi_in, output, input) \
1286         schedule(static)
1287 #endif
1288         for(int j = 0; j < roi_out->height; j++)
1289             memcpy(((char *)*output) + (size_t)out_bpp * j * roi_out->width,
1290                    ((char *)input) + (size_t)in_bpp * j * roi_in.width,
1291                    (size_t)in_bpp * roi_in.width);
1292       }
1293 #else // don't HAVE_OPENCL
1294 #ifdef _OPENMP
1295 #pragma omp parallel for default(none) \
1296       dt_omp_firstprivate(in_bpp, out_bpp) \
1297       shared(roi_out, roi_in, output, input) \
1298       schedule(static)
1299 #endif
1300       for(int j = 0; j < roi_out->height; j++)
1301             memcpy(((char *)*output) + (size_t)out_bpp * j * roi_out->width,
1302                    ((char *)input) + (size_t)in_bpp * j * roi_in.width,
1303                    (size_t)in_bpp * roi_in.width);
1304 #endif
1305 
1306       return 0;
1307     }
1308 
1309 
1310     /* get tiling requirement of module */
1311     dt_develop_tiling_t tiling = { 0 };
1312     tiling.factor_cl = tiling.maxbuf_cl = -1;	// set sentinel value to detect whether callback set sizes
1313     module->tiling_callback(module, piece, &roi_in, roi_out, &tiling);
1314     if (tiling.factor_cl < 0) tiling.factor_cl = tiling.factor; // default to CPU size if callback didn't set GPU
1315     if (tiling.maxbuf_cl < 0) tiling.maxbuf_cl = tiling.maxbuf;
1316 
1317     /* does this module involve blending? */
1318     if(piece->blendop_data && ((dt_develop_blend_params_t *)piece->blendop_data)->mask_mode != DEVELOP_MASK_DISABLED)
1319     {
1320       /* get specific memory requirement for blending */
1321       dt_develop_tiling_t tiling_blendop = { 0 };
1322       tiling_callback_blendop(module, piece, &roi_in, roi_out, &tiling_blendop);
1323 
1324       /* aggregate in structure tiling */
1325       tiling.factor = fmax(tiling.factor, tiling_blendop.factor);
1326       tiling.factor_cl = fmax(tiling.factor_cl, tiling_blendop.factor);
1327       tiling.maxbuf = fmax(tiling.maxbuf, tiling_blendop.maxbuf);
1328       tiling.maxbuf_cl = fmax(tiling.maxbuf_cl, tiling_blendop.maxbuf);
1329       tiling.overhead = fmax(tiling.overhead, tiling_blendop.overhead);
1330     }
1331 
1332     /* remark: we do not do tiling for blendop step, neither in opencl nor on cpu. if overall tiling
1333        requirements (maximum of module and blendop) require tiling for opencl path, then following blend
1334        step is anyhow done on cpu. we assume that blending itself will never require tiling in cpu path,
1335        because memory requirements will still be low enough. */
1336 
1337     assert(tiling.factor > 0.0f);
1338     assert(tiling.factor_cl > 0.0f);
1339 
1340     if(dt_atomic_get_int(&pipe->shutdown))
1341     {
1342       return 1;
1343     }
1344 
1345 #ifdef HAVE_OPENCL
1346 
1347     // Fetch RGB working profile
1348     // if input is RAW, we can't color convert because RAW is not in a color space
1349     // so we send NULL to by-pass
1350     const dt_iop_order_iccprofile_info_t *const work_profile
1351         = (input_format->cst != iop_cs_RAW) ? dt_ioppr_get_pipe_work_profile_info(pipe) : NULL;
1352 
1353     /* do we have opencl at all? did user tell us to use it? did we get a resource? */
1354     if(dt_opencl_is_inited() && pipe->opencl_enabled && pipe->devid >= 0)
1355     {
1356       int success_opencl = TRUE;
1357       dt_iop_colorspace_type_t input_cst_cl = input_format->cst;
1358 
1359       /* if input is on gpu memory only, remember this fact to later take appropriate action */
1360       int valid_input_on_gpu_only = (cl_mem_input != NULL);
1361 
1362       /* pre-check if there is enough space on device for non-tiled processing */
1363       const int fits_on_device = dt_opencl_image_fits_device(pipe->devid, MAX(roi_in.width, roi_out->width),
1364                                                              MAX(roi_in.height, roi_out->height), MAX(in_bpp, bpp),
1365                                                              tiling.factor_cl, tiling.overhead);
1366 
1367       /* general remark: in case of opencl errors within modules or out-of-memory on GPU, we transparently
1368          fall back to the respective cpu module and continue in pixelpipe. If we encounter errors we set
1369          pipe->opencl_error=1, return this function with value 1, and leave appropriate action to the calling
1370          function, which normally would restart pixelpipe without opencl.
1371          Late errors are sometimes detected when trying to get back data from device into host memory and
1372          are treated in the same manner. */
1373 
1374       /* try to enter opencl path after checking some module specific pre-requisites */
1375       if(module->process_cl && piece->process_cl_ready
1376          && !(((pipe->type & DT_DEV_PIXELPIPE_PREVIEW) == DT_DEV_PIXELPIPE_PREVIEW
1377                || (pipe->type & DT_DEV_PIXELPIPE_PREVIEW2) == DT_DEV_PIXELPIPE_PREVIEW2)
1378               && (module->flags() & IOP_FLAGS_PREVIEW_NON_OPENCL))
1379          && (fits_on_device || piece->process_tiling_ready))
1380       {
1381 
1382         // fprintf(stderr, "[opencl_pixelpipe 0] factor %f, overhead %d, width %d, height %d, bpp %d\n",
1383         // (double)tiling.factor, tiling.overhead, roi_in.width, roi_in.height, bpp);
1384 
1385         // fprintf(stderr, "[opencl_pixelpipe 1] for module `%s', have bufs %p and %p \n", module->op,
1386         // cl_mem_input, *cl_mem_output);
1387         // fprintf(stderr, "[opencl_pixelpipe 1] module '%s'\n", module->op);
1388 
1389         if(fits_on_device)
1390         {
1391           /* image is small enough -> try to directly process entire image with opencl */
1392 
1393           // fprintf(stderr, "[opencl_pixelpipe 2] module '%s' running directly with process_cl\n",
1394           // module->op);
1395 
1396           /* input is not on gpu memory -> copy it there */
1397           if(cl_mem_input == NULL)
1398           {
1399             cl_mem_input = dt_opencl_alloc_device(pipe->devid, roi_in.width, roi_in.height, in_bpp);
1400             if(cl_mem_input == NULL)
1401             {
1402               dt_print(DT_DEBUG_OPENCL, "[opencl_pixelpipe] couldn't generate input buffer for module %s\n",
1403                        module->op);
1404               success_opencl = FALSE;
1405             }
1406 
1407             if(success_opencl)
1408             {
1409               cl_int err = dt_opencl_write_host_to_device(pipe->devid, input, cl_mem_input,
1410                                                                        roi_in.width, roi_in.height, in_bpp);
1411               if(err != CL_SUCCESS)
1412               {
1413                 dt_print(DT_DEBUG_OPENCL,
1414                          "[opencl_pixelpipe] couldn't copy image to opencl device for module %s\n",
1415                          module->op);
1416                 success_opencl = FALSE;
1417               }
1418             }
1419           }
1420 
1421           if(dt_atomic_get_int(&pipe->shutdown))
1422           {
1423             dt_opencl_release_mem_object(cl_mem_input);
1424             return 1;
1425           }
1426 
1427           /* try to allocate GPU memory for output */
1428           if(success_opencl)
1429           {
1430             *cl_mem_output = dt_opencl_alloc_device(pipe->devid, roi_out->width, roi_out->height, bpp);
1431             if(*cl_mem_output == NULL)
1432             {
1433               dt_print(DT_DEBUG_OPENCL, "[opencl_pixelpipe] couldn't allocate output buffer for module %s\n",
1434                        module->op);
1435               success_opencl = FALSE;
1436             }
1437           }
1438 
1439           // fprintf(stderr, "[opencl_pixelpipe 2] for module `%s', have bufs %p and %p \n", module->op,
1440           // cl_mem_input, *cl_mem_output);
1441 
1442           // indirectly give gpu some air to breathe (and to do display related stuff)
1443           dt_iop_nap(darktable.opencl->micro_nap);
1444 
1445           // transform to input colorspace
1446           if(success_opencl)
1447           {
1448             success_opencl = dt_ioppr_transform_image_colorspace_cl(
1449                 module, piece->pipe->devid, cl_mem_input, cl_mem_input, roi_in.width, roi_in.height, input_cst_cl,
1450                 module->input_colorspace(module, pipe, piece), &input_cst_cl,
1451                 work_profile);
1452           }
1453 
1454           // histogram collection for module
1455           if(success_opencl && (dev->gui_attached || !(piece->request_histogram & DT_REQUEST_ONLY_IN_GUI))
1456              && (piece->request_histogram & DT_REQUEST_ON))
1457           {
1458             // we abuse the empty output buffer on host for intermediate storage of data in
1459             // histogram_collect_cl()
1460             size_t outbufsize = bpp * roi_out->width * roi_out->height;
1461 
1462             histogram_collect_cl(pipe->devid, piece, cl_mem_input, &roi_in, &(piece->histogram),
1463                                  piece->histogram_max, *output, outbufsize);
1464             pixelpipe_flow |= (PIXELPIPE_FLOW_HISTOGRAM_ON_GPU);
1465             pixelpipe_flow &= ~(PIXELPIPE_FLOW_HISTOGRAM_NONE | PIXELPIPE_FLOW_HISTOGRAM_ON_CPU);
1466 
1467             if(piece->histogram && (module->request_histogram & DT_REQUEST_ON)
1468                && (pipe->type & DT_DEV_PIXELPIPE_PREVIEW) == DT_DEV_PIXELPIPE_PREVIEW)
1469             {
1470               const size_t buf_size = sizeof(uint32_t) * 4 * piece->histogram_stats.bins_count;
1471               module->histogram = realloc(module->histogram, buf_size);
1472               memcpy(module->histogram, piece->histogram, buf_size);
1473               module->histogram_stats = piece->histogram_stats;
1474               memcpy(module->histogram_max, piece->histogram_max, sizeof(piece->histogram_max));
1475 
1476               if(module->widget) dt_control_queue_redraw_widget(module->widget);
1477             }
1478           }
1479 
1480           if(dt_atomic_get_int(&pipe->shutdown))
1481           {
1482             return 1;
1483           }
1484 
1485           /* now call process_cl of module; module should emit meaningful messages in case of error */
1486           if(success_opencl)
1487           {
1488             success_opencl
1489                 = module->process_cl(module, piece, cl_mem_input, *cl_mem_output, &roi_in, roi_out);
1490             pixelpipe_flow |= (PIXELPIPE_FLOW_PROCESSED_ON_GPU);
1491             pixelpipe_flow &= ~(PIXELPIPE_FLOW_PROCESSED_ON_CPU | PIXELPIPE_FLOW_PROCESSED_WITH_TILING);
1492 
1493             // and save the output colorspace
1494             pipe->dsc.cst = module->output_colorspace(module, pipe, piece);
1495           }
1496 
1497           if(dt_atomic_get_int(&pipe->shutdown))
1498           {
1499             dt_opencl_release_mem_object(cl_mem_input);
1500             return 1;
1501           }
1502 
1503           // Lab color picking for module
1504           if(success_opencl && _request_color_pick(pipe, dev, module))
1505           {
1506             // ensure that we are using the right color space
1507             dt_iop_colorspace_type_t picker_cst = _transform_for_picker(module, pipe->dsc.cst);
1508             success_opencl = dt_ioppr_transform_image_colorspace_cl(
1509                 module, piece->pipe->devid, cl_mem_input, cl_mem_input, roi_in.width, roi_in.height,
1510                 input_cst_cl, picker_cst, &input_cst_cl, work_profile);
1511             success_opencl &= dt_ioppr_transform_image_colorspace_cl(
1512                 module, piece->pipe->devid, *cl_mem_output, *cl_mem_output, roi_out->width, roi_out->height,
1513                 pipe->dsc.cst, picker_cst, &pipe->dsc.cst, work_profile);
1514 
1515             // we abuse the empty output buffer on host for intermediate storage of data in
1516             // pixelpipe_picker_cl()
1517             const size_t outbufsize = bpp * roi_out->width * roi_out->height;
1518 
1519             pixelpipe_picker_cl(pipe->devid, module, piece, &piece->dsc_in, cl_mem_input, &roi_in,
1520                                 module->picked_color, module->picked_color_min, module->picked_color_max,
1521                                 *output, outbufsize, input_cst_cl, PIXELPIPE_PICKER_INPUT);
1522             pixelpipe_picker_cl(pipe->devid, module, piece, &pipe->dsc, (*cl_mem_output), roi_out,
1523                                 module->picked_output_color, module->picked_output_color_min,
1524                                 module->picked_output_color_max, *output, outbufsize, pipe->dsc.cst,
1525                                 PIXELPIPE_PICKER_OUTPUT);
1526 
1527             DT_DEBUG_CONTROL_SIGNAL_RAISE(darktable.signals, DT_SIGNAL_CONTROL_PICKERDATA_READY, module, piece);
1528           }
1529 
1530           if(dt_atomic_get_int(&pipe->shutdown))
1531           {
1532             return 1;
1533           }
1534 
1535           // blend needs input/output images with default colorspace
1536           if(success_opencl && _transform_for_blend(module, piece))
1537           {
1538             dt_iop_colorspace_type_t blend_cst = dt_develop_blend_colorspace(piece, pipe->dsc.cst);
1539             success_opencl = dt_ioppr_transform_image_colorspace_cl(
1540                 module, piece->pipe->devid, cl_mem_input, cl_mem_input, roi_in.width, roi_in.height,
1541                 input_cst_cl, blend_cst, &input_cst_cl, work_profile);
1542             success_opencl &= dt_ioppr_transform_image_colorspace_cl(
1543                 module, piece->pipe->devid, *cl_mem_output, *cl_mem_output, roi_out->width, roi_out->height,
1544                 pipe->dsc.cst, blend_cst, &pipe->dsc.cst, work_profile);
1545           }
1546 
1547           /* process blending */
1548           if(success_opencl)
1549           {
1550             success_opencl
1551                 = dt_develop_blend_process_cl(module, piece, cl_mem_input, *cl_mem_output, &roi_in, roi_out);
1552             pixelpipe_flow |= (PIXELPIPE_FLOW_BLENDED_ON_GPU);
1553             pixelpipe_flow &= ~(PIXELPIPE_FLOW_BLENDED_ON_CPU);
1554           }
1555 
1556           /* synchronization point for opencl pipe */
1557           if(success_opencl && (!darktable.opencl->async_pixelpipe
1558                                 || (pipe->type & DT_DEV_PIXELPIPE_EXPORT) == DT_DEV_PIXELPIPE_EXPORT))
1559             success_opencl = dt_opencl_finish(pipe->devid);
1560 
1561 
1562           if(dt_atomic_get_int(&pipe->shutdown))
1563           {
1564             dt_opencl_release_mem_object(cl_mem_input);
1565             return 1;
1566           }
1567         }
1568         else if(piece->process_tiling_ready)
1569         {
1570           /* image is too big for direct opencl processing -> try to process image via tiling */
1571 
1572           // fprintf(stderr, "[opencl_pixelpipe 3] module '%s' tiling with process_tiling_cl\n", module->op);
1573 
1574           /* we might need to copy back valid image from device to host */
1575           if(cl_mem_input != NULL)
1576           {
1577             cl_int err;
1578 
1579             /* copy back to CPU buffer, then clean unneeded buffer */
1580             err = dt_opencl_copy_device_to_host(pipe->devid, input, cl_mem_input, roi_in.width, roi_in.height,
1581                                                 in_bpp);
1582             if(err != CL_SUCCESS)
1583             {
1584               /* late opencl error */
1585               dt_print(
1586                   DT_DEBUG_OPENCL,
1587                   "[opencl_pixelpipe (a)] late opencl error detected while copying back to cpu buffer: %d\n",
1588                   err);
1589               dt_opencl_release_mem_object(cl_mem_input);
1590               pipe->opencl_error = 1;
1591               return 1;
1592             }
1593             else
1594               input_format->cst = input_cst_cl;
1595             dt_opencl_release_mem_object(cl_mem_input);
1596             cl_mem_input = NULL;
1597             valid_input_on_gpu_only = FALSE;
1598           }
1599 
1600           if(dt_atomic_get_int(&pipe->shutdown))
1601           {
1602             return 1;
1603           }
1604 
1605           // indirectly give gpu some air to breathe (and to do display related stuff)
1606           dt_iop_nap(darktable.opencl->micro_nap);
1607 
1608           // transform to module input colorspace
1609           if(success_opencl)
1610           {
1611             dt_ioppr_transform_image_colorspace(module, input, input, roi_in.width, roi_in.height,
1612                                                 input_format->cst, module->input_colorspace(module, pipe, piece),
1613                                                 &input_format->cst, work_profile);
1614           }
1615 
1616           if(dt_atomic_get_int(&pipe->shutdown))
1617           {
1618             return 1;
1619           }
1620 
1621           // histogram collection for module
1622           if (success_opencl)
1623           {
1624             collect_histogram_on_CPU(pipe, dev, input, &roi_in, module, piece, &pixelpipe_flow);
1625           }
1626 
1627           if(dt_atomic_get_int(&pipe->shutdown))
1628           {
1629             return 1;
1630           }
1631 
1632           /* now call process_tiling_cl of module; module should emit meaningful messages in case of error */
1633           if(success_opencl)
1634           {
1635             success_opencl
1636                 = module->process_tiling_cl(module, piece, input, *output, &roi_in, roi_out, in_bpp);
1637             pixelpipe_flow |= (PIXELPIPE_FLOW_PROCESSED_ON_GPU | PIXELPIPE_FLOW_PROCESSED_WITH_TILING);
1638             pixelpipe_flow &= ~(PIXELPIPE_FLOW_PROCESSED_ON_CPU);
1639 
1640             // and save the output colorspace
1641             pipe->dsc.cst = module->output_colorspace(module, pipe, piece);
1642           }
1643 
1644           if(dt_atomic_get_int(&pipe->shutdown))
1645           {
1646             return 1;
1647           }
1648 
1649           // Lab color picking for module
1650           if(success_opencl && _request_color_pick(pipe, dev, module))
1651           {
1652             // ensure that we are using the right color space
1653             dt_iop_colorspace_type_t picker_cst = _transform_for_picker(module, pipe->dsc.cst);
1654             // FIXME: don't need to transform entire image colorspace when just picking a point
1655             dt_ioppr_transform_image_colorspace(module, input, input, roi_in.width, roi_in.height,
1656                                                 input_format->cst, picker_cst, &input_format->cst,
1657                                                 work_profile);
1658             dt_ioppr_transform_image_colorspace(module, *output, *output, roi_out->width, roi_out->height,
1659                                                 pipe->dsc.cst, picker_cst, &pipe->dsc.cst,
1660                                                 work_profile);
1661 
1662             pixelpipe_picker(module, piece, &piece->dsc_in, (float *)input, &roi_in, module->picked_color,
1663                              module->picked_color_min, module->picked_color_max, input_format->cst,
1664                              PIXELPIPE_PICKER_INPUT);
1665             pixelpipe_picker(module, piece, &pipe->dsc, (float *)(*output), roi_out, module->picked_output_color,
1666                              module->picked_output_color_min, module->picked_output_color_max,
1667                              pipe->dsc.cst, PIXELPIPE_PICKER_OUTPUT);
1668 
1669             DT_DEBUG_CONTROL_SIGNAL_RAISE(darktable.signals, DT_SIGNAL_CONTROL_PICKERDATA_READY, module, piece);
1670           }
1671 
1672           if(dt_atomic_get_int(&pipe->shutdown))
1673           {
1674             return 1;
1675           }
1676 
1677           // blend needs input/output images with default colorspace
1678           if(success_opencl && _transform_for_blend(module, piece))
1679           {
1680             dt_iop_colorspace_type_t blend_cst = dt_develop_blend_colorspace(piece, pipe->dsc.cst);
1681             dt_ioppr_transform_image_colorspace(module, input, input, roi_in.width, roi_in.height,
1682                                                 input_format->cst, blend_cst, &input_format->cst,
1683                                                 work_profile);
1684             dt_ioppr_transform_image_colorspace(module, *output, *output, roi_out->width, roi_out->height,
1685                                                 pipe->dsc.cst, blend_cst, &pipe->dsc.cst,
1686                                                 work_profile);
1687           }
1688 
1689           if(dt_atomic_get_int(&pipe->shutdown))
1690           {
1691             return 1;
1692           }
1693 
1694           /* do process blending on cpu (this is anyhow fast enough) */
1695           if(success_opencl)
1696           {
1697             dt_develop_blend_process(module, piece, input, *output, &roi_in, roi_out);
1698             pixelpipe_flow |= (PIXELPIPE_FLOW_BLENDED_ON_CPU);
1699             pixelpipe_flow &= ~(PIXELPIPE_FLOW_BLENDED_ON_GPU);
1700           }
1701 
1702           /* synchronization point for opencl pipe */
1703           if(success_opencl && (!darktable.opencl->async_pixelpipe
1704                                 || (pipe->type & DT_DEV_PIXELPIPE_EXPORT) == DT_DEV_PIXELPIPE_EXPORT))
1705             success_opencl = dt_opencl_finish(pipe->devid);
1706 
1707           if(dt_atomic_get_int(&pipe->shutdown))
1708           {
1709             return 1;
1710           }
1711         }
1712         else
1713         {
1714           /* image is too big for direct opencl and tiling is not allowed -> no opencl processing for this
1715            * module */
1716           success_opencl = FALSE;
1717         }
1718 
1719         if(dt_atomic_get_int(&pipe->shutdown))
1720         {
1721           dt_opencl_release_mem_object(cl_mem_input);
1722           return 1;
1723         }
1724 
1725         // if (rand() % 20 == 0) success_opencl = FALSE; // Test code: simulate spurious failures
1726 
1727         /* finally check, if we were successful */
1728         if(success_opencl)
1729         {
1730           /* Nice, everything went fine */
1731 
1732           /* this is reasonable on slow GPUs only, where it's more expensive to reprocess the whole pixelpipe
1733              than
1734              regularly copying device buffers back to host. This would slow down fast GPUs considerably.
1735              But it is worth copying data back from the GPU which is the input to the currently focused iop,
1736              as that is the iop which is most likely to change next.
1737           */
1738           if((darktable.opencl->sync_cache == OPENCL_SYNC_TRUE) ||
1739              ((darktable.opencl->sync_cache == OPENCL_SYNC_ACTIVE_MODULE) && (module == darktable.develop->gui_module)))
1740           {
1741             /* write back input into cache for faster re-usal (not for export or thumbnails) */
1742             if(cl_mem_input != NULL
1743                && (pipe->type & DT_DEV_PIXELPIPE_EXPORT) != DT_DEV_PIXELPIPE_EXPORT
1744                && (pipe->type & DT_DEV_PIXELPIPE_THUMBNAIL) != DT_DEV_PIXELPIPE_THUMBNAIL)
1745             {
1746               cl_int err;
1747 
1748               /* copy input to host memory, so we can find it in cache */
1749               err = dt_opencl_copy_device_to_host(pipe->devid, input, cl_mem_input, roi_in.width,
1750                                                   roi_in.height, in_bpp);
1751               if(err != CL_SUCCESS)
1752               {
1753                 /* late opencl error, not likely to happen here */
1754                 dt_print(DT_DEBUG_OPENCL, "[opencl_pixelpipe (e)] late opencl error detected while copying "
1755                                           "back to cpu buffer: %d\n",
1756                          err);
1757                 /* that's all we do here, we later make sure to invalidate cache line */
1758               }
1759               else
1760               {
1761                 /* success: cache line is valid now, so we will not need to invalidate it later */
1762                 valid_input_on_gpu_only = FALSE;
1763 
1764                 input_format->cst = input_cst_cl;
1765                 // TODO: check if we need to wait for finished opencl pipe before we release cl_mem_input
1766                 // dt_dev_finish(pipe->devid);
1767               }
1768             }
1769 
1770             if(dt_atomic_get_int(&pipe->shutdown))
1771             {
1772               dt_opencl_release_mem_object(cl_mem_input);
1773               return 1;
1774             }
1775           }
1776 
1777           /* we can now release cl_mem_input */
1778           dt_opencl_release_mem_object(cl_mem_input);
1779           cl_mem_input = NULL;
1780           // we speculate on the next plug-in to possibly copy back cl_mem_output to output,
1781           // so we're not just yet invalidating the (empty) output cache line.
1782         }
1783         else
1784         {
1785           /* Bad luck, opencl failed. Let's clean up and fall back to cpu module */
1786           dt_print(DT_DEBUG_OPENCL, "[opencl_pixelpipe] could not run module '%s' on gpu. falling back to cpu path\n",
1787                    module->op);
1788 
1789           // fprintf(stderr, "[opencl_pixelpipe 4] module '%s' running on cpu\n", module->op);
1790 
1791           /* we might need to free unused output buffer */
1792           if(*cl_mem_output != NULL)
1793           {
1794             dt_opencl_release_mem_object(*cl_mem_output);
1795             *cl_mem_output = NULL;
1796           }
1797 
1798           /* check where our input buffer is located */
1799           if(cl_mem_input != NULL)
1800           {
1801             cl_int err;
1802 
1803             /* copy back to host memory, then clean no longer needed opencl buffer.
1804                important info: in order to make this possible, opencl modules must
1805                not spoil their input buffer, even in case of errors. */
1806             err = dt_opencl_copy_device_to_host(pipe->devid, input, cl_mem_input, roi_in.width, roi_in.height,
1807                                                 in_bpp);
1808             if(err != CL_SUCCESS)
1809             {
1810               /* late opencl error */
1811               dt_print(
1812                   DT_DEBUG_OPENCL,
1813                   "[opencl_pixelpipe (b)] late opencl error detected while copying back to cpu buffer: %d\n",
1814                   err);
1815               dt_opencl_release_mem_object(cl_mem_input);
1816               pipe->opencl_error = 1;
1817               return 1;
1818             }
1819             else
1820               input_format->cst = input_cst_cl;
1821 
1822             /* this is a good place to release event handles as we anyhow need to move from gpu to cpu here */
1823             (void)dt_opencl_finish(pipe->devid);
1824             dt_opencl_release_mem_object(cl_mem_input);
1825             valid_input_on_gpu_only = FALSE;
1826           }
1827           if (pixelpipe_process_on_CPU(pipe, dev, input, input_format, &roi_in, output, out_format, roi_out,
1828                                        module, piece, &tiling, &pixelpipe_flow))
1829             return 1;
1830         }
1831 
1832         if(dt_atomic_get_int(&pipe->shutdown))
1833         {
1834           return 1;
1835         }
1836       }
1837       else
1838       {
1839         /* we are not allowed to use opencl for this module */
1840 
1841         // fprintf(stderr, "[opencl_pixelpipe 3] for module `%s', have bufs %p and %p \n", module->op,
1842         // cl_mem_input, *cl_mem_output);
1843 
1844         *cl_mem_output = NULL;
1845 
1846         /* cleanup unneeded opencl buffer, and copy back to CPU buffer */
1847         if(cl_mem_input != NULL)
1848         {
1849           cl_int err;
1850 
1851           err = dt_opencl_copy_device_to_host(pipe->devid, input, cl_mem_input, roi_in.width, roi_in.height,
1852                                               in_bpp);
1853           // if (rand() % 5 == 0) err = !CL_SUCCESS; // Test code: simulate spurious failures
1854           if(err != CL_SUCCESS)
1855           {
1856             /* late opencl error */
1857             dt_print(
1858                 DT_DEBUG_OPENCL,
1859                 "[opencl_pixelpipe (c)] late opencl error detected while copying back to cpu buffer: %d\n",
1860                 err);
1861             dt_opencl_release_mem_object(cl_mem_input);
1862             pipe->opencl_error = 1;
1863             return 1;
1864           }
1865           else
1866             input_format->cst = input_cst_cl;
1867 
1868           /* this is a good place to release event handles as we anyhow need to move from gpu to cpu here */
1869           (void)dt_opencl_finish(pipe->devid);
1870           dt_opencl_release_mem_object(cl_mem_input);
1871           valid_input_on_gpu_only = FALSE;
1872         }
1873 
1874         if (pixelpipe_process_on_CPU(pipe, dev, input, input_format, &roi_in, output, out_format, roi_out,
1875                                      module, piece, &tiling, &pixelpipe_flow))
1876           return 1;
1877       }
1878 
1879       /* input is still only on GPU? Let's invalidate CPU input buffer then */
1880       if(valid_input_on_gpu_only) dt_dev_pixelpipe_cache_invalidate(&(pipe->cache), input);
1881     }
1882     else
1883     {
1884       /* opencl is not inited or not enabled or we got no resource/device -> everything runs on cpu */
1885 
1886       if (pixelpipe_process_on_CPU(pipe, dev, input, input_format, &roi_in, output, out_format, roi_out,
1887                                    module, piece, &tiling, &pixelpipe_flow))
1888         return 1;
1889     }
1890 #else // HAVE_OPENCL
1891     if (pixelpipe_process_on_CPU(pipe, dev, input, input_format, &roi_in, output, out_format, roi_out,
1892                                  module, piece, &tiling, &pixelpipe_flow))
1893       return 1;
1894 #endif // HAVE_OPENCL
1895 
1896     char histogram_log[32] = "";
1897     if(!(pixelpipe_flow & PIXELPIPE_FLOW_HISTOGRAM_NONE))
1898     {
1899       snprintf(histogram_log, sizeof(histogram_log), ", collected histogram on %s",
1900                (pixelpipe_flow & PIXELPIPE_FLOW_HISTOGRAM_ON_GPU
1901                     ? "GPU"
1902                     : pixelpipe_flow & PIXELPIPE_FLOW_HISTOGRAM_ON_CPU ? "CPU" : ""));
1903     }
1904 
1905     gchar *module_label = dt_history_item_get_name(module);
1906     dt_show_times_f(
1907         &start, "[dev_pixelpipe]", "processed `%s' on %s%s%s, blended on %s [%s]", module_label,
1908         pixelpipe_flow & PIXELPIPE_FLOW_PROCESSED_ON_GPU
1909             ? "GPU"
1910             : pixelpipe_flow & PIXELPIPE_FLOW_PROCESSED_ON_CPU ? "CPU" : "",
1911         pixelpipe_flow & PIXELPIPE_FLOW_PROCESSED_WITH_TILING ? " with tiling" : "",
1912         (!(pixelpipe_flow & PIXELPIPE_FLOW_HISTOGRAM_NONE) && (piece->request_histogram & DT_REQUEST_ON))
1913             ? histogram_log
1914             : "",
1915         pixelpipe_flow & PIXELPIPE_FLOW_BLENDED_ON_GPU
1916             ? "GPU"
1917             : pixelpipe_flow & PIXELPIPE_FLOW_BLENDED_ON_CPU ? "CPU" : "",
1918         _pipe_type_to_str(pipe->type));
1919     g_free(module_label);
1920     module_label = NULL;
1921 
1922     // in case we get this buffer from the cache in the future, cache some stuff:
1923     **out_format = piece->dsc_out = pipe->dsc;
1924 
1925     if(module == darktable.develop->gui_module)
1926     {
1927       // give the input buffer to the currently focused plugin more weight.
1928       // the user is likely to change that one soon, so keep it in cache.
1929       dt_dev_pixelpipe_cache_reweight(&(pipe->cache), input);
1930     }
1931 #ifndef _DEBUG
1932     if(darktable.unmuted & DT_DEBUG_NAN)
1933 #endif
1934     {
1935       if(dt_atomic_get_int(&pipe->shutdown))
1936       {
1937         return 1;
1938       }
1939 
1940       if(strcmp(module->op, "gamma") == 0)
1941       {
1942         goto post_process_collect_info;
1943       }
1944 
1945 #ifdef HAVE_OPENCL
1946       if(*cl_mem_output != NULL)
1947         dt_opencl_copy_device_to_host(pipe->devid, *output, *cl_mem_output, roi_out->width, roi_out->height, bpp);
1948 #endif
1949 
1950       if((*out_format)->datatype == TYPE_FLOAT && (*out_format)->channels == 4)
1951       {
1952         int hasinf = 0, hasnan = 0;
1953         dt_aligned_pixel_t min = { FLT_MAX };
1954         dt_aligned_pixel_t max = { FLT_MIN };
1955 
1956         for(int k = 0; k < 4 * roi_out->width * roi_out->height; k++)
1957         {
1958           if((k & 3) < 3)
1959           {
1960             float f = ((float *)(*output))[k];
1961             if(isnan(f))
1962               hasnan = 1;
1963             else if(isinf(f))
1964               hasinf = 1;
1965             else
1966             {
1967               min[k & 3] = fmin(f, min[k & 3]);
1968               max[k & 3] = fmax(f, max[k & 3]);
1969             }
1970           }
1971         }
1972         module_label = dt_history_item_get_name(module);
1973         if(hasnan)
1974           fprintf(stderr, "[dev_pixelpipe] module `%s' outputs NaNs! [%s]\n", module_label,
1975                   _pipe_type_to_str(pipe->type));
1976         if(hasinf)
1977           fprintf(stderr, "[dev_pixelpipe] module `%s' outputs non-finite floats! [%s]\n", module_label,
1978                   _pipe_type_to_str(pipe->type));
1979         fprintf(stderr, "[dev_pixelpipe] module `%s' min: (%f; %f; %f) max: (%f; %f; %f) [%s]\n", module_label,
1980                 min[0], min[1], min[2], max[0], max[1], max[2], _pipe_type_to_str(pipe->type));
1981         g_free(module_label);
1982       }
1983       else if((*out_format)->datatype == TYPE_FLOAT && (*out_format)->channels == 1)
1984       {
1985         int hasinf = 0, hasnan = 0;
1986         float min = FLT_MAX;
1987         float max = FLT_MIN;
1988 
1989         for(int k = 0; k < roi_out->width * roi_out->height; k++)
1990         {
1991           float f = ((float *)(*output))[k];
1992           if(isnan(f))
1993             hasnan = 1;
1994           else if(isinf(f))
1995             hasinf = 1;
1996           else
1997           {
1998             min = fmin(f, min);
1999             max = fmax(f, max);
2000           }
2001         }
2002         module_label = dt_history_item_get_name(module);
2003         if(hasnan)
2004           fprintf(stderr, "[dev_pixelpipe] module `%s' outputs NaNs! [%s]\n", module_label,
2005                   _pipe_type_to_str(pipe->type));
2006         if(hasinf)
2007           fprintf(stderr, "[dev_pixelpipe] module `%s' outputs non-finite floats! [%s]\n", module_label,
2008                   _pipe_type_to_str(pipe->type));
2009         fprintf(stderr, "[dev_pixelpipe] module `%s' min: (%f) max: (%f) [%s]\n", module_label, min, max,
2010                 _pipe_type_to_str(pipe->type));
2011         g_free(module_label);
2012       }
2013     }
2014 
2015 post_process_collect_info:
2016 
2017     if(dt_atomic_get_int(&pipe->shutdown))
2018     {
2019       return 1;
2020     }
2021     // Pick RGB/Lab for the primary colorpicker and live samples
2022     if(dev->gui_attached && pipe == dev->preview_pipe
2023        && (strcmp(module->op, "gamma") == 0) // only gamma provides meaningful RGB data
2024        && input)
2025     {
2026       if(darktable.lib->proxy.colorpicker.picker_proxy || darktable.lib->proxy.colorpicker.live_samples)
2027         _pixelpipe_pick_samples(dev, module, (const float *const )input, &roi_in);
2028     }
2029 
2030     // 4) final histogram:
2031     if(dt_atomic_get_int(&pipe->shutdown))
2032     {
2033       return 1;
2034     }
2035     if(dev->gui_attached && !dev->gui_leaving && pipe == dev->preview_pipe && (strcmp(module->op, "gamma") == 0))
2036     {
2037       // FIXME: read this from dt_ioppr_get_pipe_output_profile_info()?
2038       const dt_iop_order_iccprofile_info_t *const display_profile
2039         = dt_ioppr_add_profile_info_to_list(dev, darktable.color_profiles->display_type,
2040                                             darktable.color_profiles->display_filename, INTENT_RELATIVE_COLORIMETRIC);
2041 
2042       // Since histogram is being treated as the second-to-last link
2043       // in the pixelpipe and has a "process" call, why not treat it
2044       // as an iop? Granted, other views such as tether may also
2045       // benefit via a histogram.
2046       if(input == NULL)
2047       {
2048         // FIXME: really get rid of this case -- colorpicker does just fine with skipping when (if??) input is NULL
2049         // input may not be available, so we use the output from gamma
2050         // this may lead to some rounding errors
2051         // FIXME: under what circumstances would input not be available? when this iop's result is pulled in from cache?
2052         float *const buf = dt_alloc_align_float((size_t)4 * roi_out->width * roi_out->height);
2053         if(buf)
2054         {
2055           const uint8_t *in = (uint8_t *)(*output);
2056           // FIXME: it would be nice to use dt_imageio_flip_buffers_ui8_to_float() but then we'd need to make another pass to convert RGB to BGR
2057           #ifdef _OPENMP
2058           #pragma omp parallel for default(none) dt_omp_firstprivate(buf, in, roi_out) schedule(simd:static)
2059           #endif
2060           for(size_t k = 0; k < (size_t)roi_out->width * roi_out->height * 4; k += 4)
2061           {
2062             for_four_channels(c, aligned(in, buf:64)) buf[k + c] = (float)in[k + 2 - c] / 255.0f;
2063           }
2064           darktable.lib->proxy.histogram.process(darktable.lib->proxy.histogram.module, buf,
2065                                                  roi_out->width, roi_out->height,
2066                                                  display_profile, dt_ioppr_get_histogram_profile_info(dev));
2067           dt_free_align(buf);
2068         }
2069       }
2070       else
2071       {
2072         darktable.lib->proxy.histogram.process(darktable.lib->proxy.histogram.module, input,
2073                                                roi_in.width, roi_in.height,
2074                                                display_profile, dt_ioppr_get_histogram_profile_info(dev));
2075       }
2076     }
2077   }
2078 
2079   if(dt_atomic_get_int(&pipe->shutdown))
2080     return 1;
2081 
2082   return 0;
2083 }
2084 
2085 
dt_dev_pixelpipe_process_no_gamma(dt_dev_pixelpipe_t * pipe,dt_develop_t * dev,int x,int y,int width,int height,float scale)2086 int dt_dev_pixelpipe_process_no_gamma(dt_dev_pixelpipe_t *pipe, dt_develop_t *dev, int x, int y, int width,
2087                                       int height, float scale)
2088 {
2089   // temporarily disable gamma mapping.
2090   GList *gammap = g_list_last(pipe->nodes);
2091   dt_dev_pixelpipe_iop_t *gamma = (dt_dev_pixelpipe_iop_t *)gammap->data;
2092   while(strcmp(gamma->module->op, "gamma"))
2093   {
2094     gamma = NULL;
2095     gammap = g_list_previous(gammap);
2096     if(!gammap) break;
2097     gamma = (dt_dev_pixelpipe_iop_t *)gammap->data;
2098   }
2099   if(gamma) gamma->enabled = 0;
2100   const int ret = dt_dev_pixelpipe_process(pipe, dev, x, y, width, height, scale);
2101   if(gamma) gamma->enabled = 1;
2102   return ret;
2103 }
2104 
dt_dev_pixelpipe_disable_after(dt_dev_pixelpipe_t * pipe,const char * op)2105 void dt_dev_pixelpipe_disable_after(dt_dev_pixelpipe_t *pipe, const char *op)
2106 {
2107   GList *nodes = g_list_last(pipe->nodes);
2108   dt_dev_pixelpipe_iop_t *piece = (dt_dev_pixelpipe_iop_t *)nodes->data;
2109   while(strcmp(piece->module->op, op))
2110   {
2111     piece->enabled = 0;
2112     piece = NULL;
2113     nodes = g_list_previous(nodes);
2114     if(!nodes) break;
2115     piece = (dt_dev_pixelpipe_iop_t *)nodes->data;
2116   }
2117 }
2118 
dt_dev_pixelpipe_disable_before(dt_dev_pixelpipe_t * pipe,const char * op)2119 void dt_dev_pixelpipe_disable_before(dt_dev_pixelpipe_t *pipe, const char *op)
2120 {
2121   GList *nodes = pipe->nodes;
2122   dt_dev_pixelpipe_iop_t *piece = (dt_dev_pixelpipe_iop_t *)nodes->data;
2123   while(strcmp(piece->module->op, op))
2124   {
2125     piece->enabled = 0;
2126     piece = NULL;
2127     nodes = g_list_next(nodes);
2128     if(!nodes) break;
2129     piece = (dt_dev_pixelpipe_iop_t *)nodes->data;
2130   }
2131 }
2132 
dt_dev_pixelpipe_process_rec_and_backcopy(dt_dev_pixelpipe_t * pipe,dt_develop_t * dev,void ** output,void ** cl_mem_output,dt_iop_buffer_dsc_t ** out_format,const dt_iop_roi_t * roi_out,GList * modules,GList * pieces,int pos)2133 static int dt_dev_pixelpipe_process_rec_and_backcopy(dt_dev_pixelpipe_t *pipe, dt_develop_t *dev, void **output,
2134                                                      void **cl_mem_output, dt_iop_buffer_dsc_t **out_format,
2135                                                      const dt_iop_roi_t *roi_out, GList *modules, GList *pieces,
2136                                                      int pos)
2137 {
2138   dt_pthread_mutex_lock(&pipe->busy_mutex);
2139   int ret = dt_dev_pixelpipe_process_rec(pipe, dev, output, cl_mem_output, out_format, roi_out, modules, pieces, pos);
2140 #ifdef HAVE_OPENCL
2141   // copy back final opencl buffer (if any) to CPU
2142   if(ret)
2143   {
2144     dt_opencl_release_mem_object(*cl_mem_output);
2145     *cl_mem_output = NULL;
2146   }
2147   else
2148   {
2149     if(*cl_mem_output != NULL)
2150     {
2151       cl_int err;
2152 
2153       err = dt_opencl_copy_device_to_host(pipe->devid, *output, *cl_mem_output, roi_out->width, roi_out->height,
2154                                           dt_iop_buffer_dsc_to_bpp(*out_format));
2155       dt_opencl_release_mem_object(*cl_mem_output);
2156       *cl_mem_output = NULL;
2157 
2158       if(err != CL_SUCCESS)
2159       {
2160         /* this indicates a opencl problem earlier in the pipeline */
2161         dt_print(DT_DEBUG_OPENCL,
2162                  "[opencl_pixelpipe (d)] late opencl error detected while copying back to cpu buffer: %d\n",
2163                  err);
2164         pipe->opencl_error = 1;
2165         ret = 1;
2166       }
2167     }
2168   }
2169 #endif
2170   dt_pthread_mutex_unlock(&pipe->busy_mutex);
2171   return ret;
2172 }
2173 
2174 
dt_dev_pixelpipe_process(dt_dev_pixelpipe_t * pipe,dt_develop_t * dev,int x,int y,int width,int height,float scale)2175 int dt_dev_pixelpipe_process(dt_dev_pixelpipe_t *pipe, dt_develop_t *dev, int x, int y, int width, int height,
2176                              float scale)
2177 {
2178   pipe->processing = 1;
2179   pipe->opencl_enabled = dt_opencl_update_settings(); // update enabled flag and profile from preferences
2180   pipe->devid = (pipe->opencl_enabled) ? dt_opencl_lock_device(pipe->type)
2181                                        : -1; // try to get/lock opencl resource
2182 
2183   dt_print(DT_DEBUG_OPENCL, "[pixelpipe_process] [%s] using device %d\n", _pipe_type_to_str(pipe->type),
2184            pipe->devid);
2185 
2186   if(darktable.unmuted & DT_DEBUG_MEMORY)
2187   {
2188     fprintf(stderr, "[memory] before pixelpipe process\n");
2189     dt_print_mem_usage();
2190   }
2191 
2192   if(pipe->devid >= 0) dt_opencl_events_reset(pipe->devid);
2193 
2194   dt_iop_roi_t roi = (dt_iop_roi_t){ x, y, width, height, scale };
2195   // printf("pixelpipe homebrew process start\n");
2196   if(darktable.unmuted & DT_DEBUG_DEV) dt_dev_pixelpipe_cache_print(&pipe->cache);
2197 
2198   // get a snapshot of mask list
2199   if(pipe->forms) g_list_free_full(pipe->forms, (void (*)(void *))dt_masks_free_form);
2200   pipe->forms = dt_masks_dup_forms_deep(dev->forms, NULL);
2201 
2202   //  go through list of modules from the end:
2203   const guint pos = g_list_length(pipe->iop);
2204   GList *modules = g_list_last(pipe->iop);
2205   GList *pieces = g_list_last(pipe->nodes);
2206 
2207 // re-entry point: in case of late opencl errors we start all over again with opencl-support disabled
2208 restart:
2209 
2210   // check if we should obsolete caches
2211   if(pipe->cache_obsolete) dt_dev_pixelpipe_cache_flush(&(pipe->cache));
2212   pipe->cache_obsolete = 0;
2213 
2214   // mask display off as a starting point
2215   pipe->mask_display = DT_DEV_PIXELPIPE_DISPLAY_NONE;
2216   // and blendif active
2217   pipe->bypass_blendif = 0;
2218 
2219   void *buf = NULL;
2220   void *cl_mem_out = NULL;
2221 
2222   dt_iop_buffer_dsc_t _out_format = { 0 };
2223   dt_iop_buffer_dsc_t *out_format = &_out_format;
2224 
2225   // run pixelpipe recursively and get error status
2226   const int err =
2227     dt_dev_pixelpipe_process_rec_and_backcopy(pipe, dev, &buf, &cl_mem_out, &out_format, &roi, modules,
2228                                               pieces, pos);
2229 
2230   // get status summary of opencl queue by checking the eventlist
2231   const int oclerr = (pipe->devid >= 0) ? (dt_opencl_events_flush(pipe->devid, 1) != 0) : 0;
2232 
2233   // Check if we had opencl errors ....
2234   // remark: opencl errors can come in two ways: pipe->opencl_error is TRUE (and err is TRUE) OR oclerr is
2235   // TRUE
2236   if(oclerr || (err && pipe->opencl_error))
2237   {
2238     // Well, there were errors -> we might need to free an invalid opencl memory object
2239     dt_opencl_release_mem_object(cl_mem_out);
2240     dt_opencl_unlock_device(pipe->devid); // release opencl resource
2241     dt_pthread_mutex_lock(&pipe->busy_mutex);
2242     pipe->opencl_enabled = 0; // disable opencl for this pipe
2243     pipe->opencl_error = 0;   // reset error status
2244     pipe->devid = -1;
2245     dt_pthread_mutex_unlock(&pipe->busy_mutex);
2246 
2247     darktable.opencl->error_count++; // increase error count
2248     if(darktable.opencl->error_count >= DT_OPENCL_MAX_ERRORS)
2249     {
2250       // too frequent opencl errors encountered: this is a clear sign of a broken setup. give up on opencl
2251       // during this session.
2252       darktable.opencl->stopped = 1;
2253       dt_print(DT_DEBUG_OPENCL,
2254                "[opencl] frequent opencl errors encountered; disabling opencl for this session!\n");
2255       dt_control_log(
2256           _("darktable discovered problems with your OpenCL setup; disabling OpenCL for this session!"));
2257       // also remove "opencl" from capabilities so that the preference entry is greyed out
2258       dt_capabilities_remove("opencl");
2259     }
2260 
2261     dt_dev_pixelpipe_flush_caches(pipe);
2262     dt_dev_pixelpipe_change(pipe, dev);
2263     dt_print(DT_DEBUG_OPENCL, "[pixelpipe_process] [%s] falling back to cpu path\n",
2264              _pipe_type_to_str(pipe->type));
2265     goto restart; // try again (this time without opencl)
2266   }
2267 
2268   // release resources:
2269   if (pipe->forms)
2270   {
2271     g_list_free_full(pipe->forms, (void (*)(void *))dt_masks_free_form);
2272     pipe->forms = NULL;
2273   }
2274   if(pipe->devid >= 0)
2275   {
2276     dt_opencl_unlock_device(pipe->devid);
2277     pipe->devid = -1;
2278   }
2279   // ... and in case of other errors ...
2280   if(err)
2281   {
2282     pipe->processing = 0;
2283     return 1;
2284   }
2285 
2286   // terminate
2287   dt_pthread_mutex_lock(&pipe->backbuf_mutex);
2288   pipe->backbuf_hash = dt_dev_pixelpipe_cache_hash(pipe->image.id, &roi, pipe, 0);
2289   pipe->backbuf = buf;
2290   pipe->backbuf_width = width;
2291   pipe->backbuf_height = height;
2292 
2293   if((pipe->type & DT_DEV_PIXELPIPE_PREVIEW) == DT_DEV_PIXELPIPE_PREVIEW
2294      || (pipe->type & DT_DEV_PIXELPIPE_FULL) == DT_DEV_PIXELPIPE_FULL
2295      || (pipe->type & DT_DEV_PIXELPIPE_PREVIEW2) == DT_DEV_PIXELPIPE_PREVIEW2)
2296   {
2297     if(pipe->output_backbuf == NULL || pipe->output_backbuf_width != pipe->backbuf_width || pipe->output_backbuf_height != pipe->backbuf_height)
2298     {
2299       g_free(pipe->output_backbuf);
2300       pipe->output_backbuf_width = pipe->backbuf_width;
2301       pipe->output_backbuf_height = pipe->backbuf_height;
2302       pipe->output_backbuf = g_malloc0(sizeof(uint8_t) * 4 * pipe->output_backbuf_width * pipe->output_backbuf_height);
2303     }
2304 
2305     if(pipe->output_backbuf)
2306       memcpy(pipe->output_backbuf, pipe->backbuf, sizeof(uint8_t) * 4 * pipe->output_backbuf_width * pipe->output_backbuf_height);
2307     pipe->output_imgid = pipe->image.id;
2308   }
2309   dt_pthread_mutex_unlock(&pipe->backbuf_mutex);
2310 
2311   // printf("pixelpipe homebrew process end\n");
2312   pipe->processing = 0;
2313   return 0;
2314 }
2315 
dt_dev_pixelpipe_flush_caches(dt_dev_pixelpipe_t * pipe)2316 void dt_dev_pixelpipe_flush_caches(dt_dev_pixelpipe_t *pipe)
2317 {
2318   dt_dev_pixelpipe_cache_flush(&pipe->cache);
2319 }
2320 
dt_dev_pixelpipe_get_dimensions(dt_dev_pixelpipe_t * pipe,struct dt_develop_t * dev,int width_in,int height_in,int * width,int * height)2321 void dt_dev_pixelpipe_get_dimensions(dt_dev_pixelpipe_t *pipe, struct dt_develop_t *dev, int width_in,
2322                                      int height_in, int *width, int *height)
2323 {
2324   dt_pthread_mutex_lock(&pipe->busy_mutex);
2325   dt_iop_roi_t roi_in = (dt_iop_roi_t){ 0, 0, width_in, height_in, 1.0 };
2326   dt_iop_roi_t roi_out;
2327   GList *modules = pipe->iop;
2328   GList *pieces = pipe->nodes;
2329   while(modules)
2330   {
2331     dt_iop_module_t *module = (dt_iop_module_t *)modules->data;
2332     dt_dev_pixelpipe_iop_t *piece = (dt_dev_pixelpipe_iop_t *)pieces->data;
2333 
2334     piece->buf_in = roi_in;
2335 
2336     // skip this module?
2337     if(piece->enabled
2338        && !(dev->gui_module && dev->gui_module != module
2339             && dev->gui_module->operation_tags_filter() & module->operation_tags()))
2340     {
2341       module->modify_roi_out(module, piece, &roi_out, &roi_in);
2342     }
2343     else
2344     {
2345       // pass through regions of interest for gui post expose events
2346       roi_out = roi_in;
2347     }
2348 
2349     piece->buf_out = roi_out;
2350     roi_in = roi_out;
2351 
2352     modules = g_list_next(modules);
2353     pieces = g_list_next(pieces);
2354   }
2355   *width = roi_out.width;
2356   *height = roi_out.height;
2357   dt_pthread_mutex_unlock(&pipe->busy_mutex);
2358 }
2359 
dt_dev_get_raster_mask(const 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)2360 float *dt_dev_get_raster_mask(const dt_dev_pixelpipe_t *pipe, const dt_iop_module_t *raster_mask_source,
2361                               const int raster_mask_id, const dt_iop_module_t *target_module,
2362                               gboolean *free_mask)
2363 {
2364   if(!raster_mask_source)
2365     return NULL;
2366 
2367   *free_mask = FALSE;
2368   float *raster_mask = NULL;
2369 
2370   GList *source_iter;
2371   for(source_iter = pipe->nodes; source_iter; source_iter = g_list_next(source_iter))
2372   {
2373     const dt_dev_pixelpipe_iop_t *candidate = (dt_dev_pixelpipe_iop_t *)source_iter->data;
2374     if(candidate->module == raster_mask_source)
2375       break;
2376   }
2377 
2378   if(source_iter)
2379   {
2380     const dt_dev_pixelpipe_iop_t *source_piece = (dt_dev_pixelpipe_iop_t *)source_iter->data;
2381     if(source_piece && source_piece->enabled) // there might be stale masks from disabled modules left over. don't use those!
2382     {
2383       raster_mask = g_hash_table_lookup(source_piece->raster_masks, GINT_TO_POINTER(raster_mask_id));
2384       if(raster_mask)
2385       {
2386         for(GList *iter = g_list_next(source_iter); iter; iter = g_list_next(iter))
2387         {
2388           dt_dev_pixelpipe_iop_t *module = (dt_dev_pixelpipe_iop_t *)iter->data;
2389 
2390           if(module->enabled
2391              && !(module->module->dev->gui_module && module->module->dev->gui_module != module->module
2392                   && (module->module->dev->gui_module->operation_tags_filter() & module->module->operation_tags())))
2393           {
2394             if(module->module->distort_mask
2395               && !(!strcmp(module->module->op, "finalscale") // hack against pipes not using finalscale
2396                     && module->processed_roi_in.width == 0
2397                     && module->processed_roi_in.height == 0))
2398             {
2399               float *transformed_mask = dt_alloc_align_float((size_t)module->processed_roi_out.width
2400                                                               * module->processed_roi_out.height);
2401               module->module->distort_mask(module->module,
2402                                           module,
2403                                           raster_mask,
2404                                           transformed_mask,
2405                                           &module->processed_roi_in,
2406                                           &module->processed_roi_out);
2407               if(*free_mask) dt_free_align(raster_mask);
2408               *free_mask = TRUE;
2409               raster_mask = transformed_mask;
2410             }
2411             else if(!module->module->distort_mask &&
2412                     (module->processed_roi_in.width != module->processed_roi_out.width ||
2413                      module->processed_roi_in.height != module->processed_roi_out.height ||
2414                      module->processed_roi_in.x != module->processed_roi_out.x ||
2415                      module->processed_roi_in.y != module->processed_roi_out.y))
2416               fprintf(stderr, "FIXME: module `%s' changed the roi from %d x %d @ %d / %d to %d x %d | %d / %d but doesn't have "
2417                      "distort_mask() implemented!\n", module->module->op, module->processed_roi_in.width,
2418                      module->processed_roi_in.height, module->processed_roi_in.x, module->processed_roi_in.y,
2419                      module->processed_roi_out.width, module->processed_roi_out.height, module->processed_roi_out.x,
2420                      module->processed_roi_out.y);
2421           }
2422 
2423           if(module->module == target_module)
2424             break;
2425         }
2426       }
2427     }
2428   }
2429 
2430   return raster_mask;
2431 }
2432 
dt_dev_clear_rawdetail_mask(dt_dev_pixelpipe_t * pipe)2433 void dt_dev_clear_rawdetail_mask(dt_dev_pixelpipe_t *pipe)
2434 {
2435   if(pipe->rawdetail_mask_data) dt_free_align(pipe->rawdetail_mask_data);
2436   pipe->rawdetail_mask_data = NULL;
2437 }
2438 
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)2439 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)
2440 {
2441   dt_dev_pixelpipe_t *p = piece->pipe;
2442   const gboolean info = ((darktable.unmuted & DT_DEBUG_MASKS) && (piece->pipe->type == DT_DEV_PIXELPIPE_FULL));
2443 
2444   if((p->want_detail_mask & DT_DEV_DETAIL_MASK_REQUIRED) == 0)
2445   {
2446     if(p->rawdetail_mask_data)
2447     {
2448       fprintf(stderr, "[dt_dev_write_rawdetail_mask] detail mask not required but found old data %p\n", p->rawdetail_mask_data);
2449       dt_dev_clear_rawdetail_mask(p);
2450     }
2451     return FALSE;
2452   }
2453   if((p->want_detail_mask & ~DT_DEV_DETAIL_MASK_REQUIRED) != mode) return FALSE;
2454 
2455   if(info) fprintf(stderr, "[dt_dev_write_rawdetail_mask] %i (%ix%i), olddata %p", mode, roi_in->width, roi_in->height, p->rawdetail_mask_data);
2456   dt_dev_clear_rawdetail_mask(p);
2457 
2458   const int width = roi_in->width;
2459   const int height = roi_in->height;
2460   float *mask = dt_alloc_align_float((size_t)width * height);
2461   float *tmp = dt_alloc_align_float((size_t)width * height);
2462   if((mask == NULL) || (tmp == NULL)) goto error;
2463 
2464   p->rawdetail_mask_data = mask;
2465   memcpy(&p->rawdetail_mask_roi, roi_in, sizeof(dt_iop_roi_t));
2466 
2467   dt_aligned_pixel_t wb = { piece->pipe->dsc.temperature.coeffs[0],
2468                             piece->pipe->dsc.temperature.coeffs[1],
2469                             piece->pipe->dsc.temperature.coeffs[2] };
2470   if((p->want_detail_mask & ~DT_DEV_DETAIL_MASK_REQUIRED) == DT_DEV_DETAIL_MASK_RAWPREPARE)
2471   {
2472     wb[0] = wb[1] = wb[2] = 1.0f;
2473   }
2474   dt_masks_calc_rawdetail_mask(rgb, mask, tmp, width, height, wb);
2475   dt_free_align(tmp);
2476   if(info) fprintf(stderr, " done\n");
2477   return FALSE;
2478 
2479   error:
2480   if(info) fprintf(stderr, " ERROR\n");
2481   dt_free_align(mask);
2482   dt_free_align(tmp);
2483   return TRUE;
2484 }
2485 
2486 #ifdef HAVE_OPENCL
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)2487 gboolean 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)
2488 {
2489   dt_dev_pixelpipe_t *p = piece->pipe;
2490   const gboolean info = ((darktable.unmuted & DT_DEBUG_MASKS) && (piece->pipe->type == DT_DEV_PIXELPIPE_FULL));
2491 
2492   if((p->want_detail_mask & DT_DEV_DETAIL_MASK_REQUIRED) == 0)
2493   {
2494     if(p->rawdetail_mask_data)
2495     {
2496       if(info) fprintf(stderr, "[dt_dev_write_rawdetail_mask_cl] detail mask not required but found old data %p\n", p->rawdetail_mask_data);
2497       dt_dev_clear_rawdetail_mask(p);
2498     }
2499     return FALSE;
2500   }
2501 
2502   if((p->want_detail_mask & ~DT_DEV_DETAIL_MASK_REQUIRED) != mode) return FALSE;
2503 
2504   if(info) fprintf(stderr, "[dt_dev_write_rawdetail_mask_cl] mode %i (%ix%i), olddata %p", mode, roi_in->width, roi_in->height, p->rawdetail_mask_data);
2505   dt_dev_clear_rawdetail_mask(p);
2506 
2507   const int width = roi_in->width;
2508   const int height = roi_in->height;
2509 
2510   cl_mem out = NULL;
2511   cl_mem tmp = NULL;
2512   float *mask = NULL;
2513   const int devid = p->devid;
2514 
2515   mask = dt_alloc_align_float((size_t)width * height);
2516   if(mask == NULL) goto error;
2517   out = dt_opencl_alloc_device(devid, width, height, sizeof(float));
2518   if(out == NULL) goto error;
2519   tmp = dt_opencl_alloc_device_buffer(devid, sizeof(float) * width * height);
2520   if(tmp == NULL) goto error;
2521   {
2522     const int kernel = darktable.opencl->blendop->kernel_calc_Y0_mask;
2523     dt_aligned_pixel_t wb = { piece->pipe->dsc.temperature.coeffs[0],
2524                               piece->pipe->dsc.temperature.coeffs[1],
2525                               piece->pipe->dsc.temperature.coeffs[2] };
2526     if((p->want_detail_mask & ~DT_DEV_DETAIL_MASK_REQUIRED) == DT_DEV_DETAIL_MASK_RAWPREPARE)
2527     {
2528       wb[0] = wb[1] = wb[2] = 1.0f;
2529     }
2530     size_t sizes[3] = { ROUNDUPWD(width), ROUNDUPHT(height), 1 };
2531     dt_opencl_set_kernel_arg(devid, kernel, 0, sizeof(cl_mem), &tmp);
2532     dt_opencl_set_kernel_arg(devid, kernel, 1, sizeof(cl_mem), &in);
2533     dt_opencl_set_kernel_arg(devid, kernel, 2, sizeof(int), &width);
2534     dt_opencl_set_kernel_arg(devid, kernel, 3, sizeof(int), &height);
2535     dt_opencl_set_kernel_arg(devid, kernel, 4, sizeof(float), &wb[0]);
2536     dt_opencl_set_kernel_arg(devid, kernel, 5, sizeof(float), &wb[1]);
2537     dt_opencl_set_kernel_arg(devid, kernel, 6, sizeof(float), &wb[2]);
2538     const int err = dt_opencl_enqueue_kernel_2d(devid, kernel, sizes);
2539     if(err != CL_SUCCESS) goto error;
2540   }
2541   {
2542     size_t sizes[3] = { ROUNDUPWD(width), ROUNDUPHT(height), 1 };
2543     const int kernel = darktable.opencl->blendop->kernel_write_scharr_mask;
2544     dt_opencl_set_kernel_arg(devid, kernel, 0, sizeof(cl_mem), &tmp);
2545     dt_opencl_set_kernel_arg(devid, kernel, 1, sizeof(cl_mem), &out);
2546     dt_opencl_set_kernel_arg(devid, kernel, 2, sizeof(int), &width);
2547     dt_opencl_set_kernel_arg(devid, kernel, 3, sizeof(int), &height);
2548     const int err = dt_opencl_enqueue_kernel_2d(devid, kernel, sizes);
2549     if(err != CL_SUCCESS) return FALSE;
2550   }
2551 
2552   {
2553     const int err = dt_opencl_read_host_from_device(devid, mask, out, width, height, sizeof(float));
2554     if(err != CL_SUCCESS) goto error;
2555   }
2556 
2557   p->rawdetail_mask_data = mask;
2558   memcpy(&p->rawdetail_mask_roi, roi_in, sizeof(dt_iop_roi_t));
2559 
2560   dt_opencl_release_mem_object(out);
2561   dt_opencl_release_mem_object(tmp);
2562   if(info) fprintf(stderr, " done\n");
2563   return FALSE;
2564 
2565   error:
2566   if(info) fprintf(stderr, " ERROR\n");
2567   dt_dev_clear_rawdetail_mask(p);
2568   dt_opencl_release_mem_object(out);
2569   dt_opencl_release_mem_object(tmp);
2570   dt_free_align(mask);
2571   return TRUE;
2572 }
2573 #endif
2574 
2575 // this expects a mask prepared by the demosaicer and distorts the mask through all pipeline modules
2576 // until target
dt_dev_distort_detail_mask(const dt_dev_pixelpipe_t * pipe,float * src,const dt_iop_module_t * target_module)2577 float *dt_dev_distort_detail_mask(const dt_dev_pixelpipe_t *pipe, float *src, const dt_iop_module_t *target_module)
2578 {
2579   if(!pipe->rawdetail_mask_data) return NULL;
2580   const gboolean info = ((darktable.unmuted & DT_DEBUG_MASKS) && (pipe->type == DT_DEV_PIXELPIPE_FULL));
2581 
2582   gboolean valid = FALSE;
2583   const int check = pipe->want_detail_mask & ~DT_DEV_DETAIL_MASK_REQUIRED;
2584 
2585   GList *source_iter;
2586   for(source_iter = pipe->nodes; source_iter; source_iter = g_list_next(source_iter))
2587   {
2588     const dt_dev_pixelpipe_iop_t *candidate = (dt_dev_pixelpipe_iop_t *)source_iter->data;
2589     if(((!strcmp(candidate->module->op, "demosaic")) && candidate->enabled) && (check == DT_DEV_DETAIL_MASK_DEMOSAIC))
2590     {
2591       valid = TRUE;
2592       break;
2593     }
2594     if(((!strcmp(candidate->module->op, "rawprepare")) && candidate->enabled) && (check == DT_DEV_DETAIL_MASK_RAWPREPARE))
2595     {
2596       valid = TRUE;
2597       break;
2598     }
2599   }
2600 
2601   if(!valid) return NULL;
2602   if(info) fprintf(stderr, "[dt_dev_distort_detail_mask] (%ix%i) for module %s: ", pipe->rawdetail_mask_roi.width, pipe->rawdetail_mask_roi.height, target_module->op);
2603 
2604   float *resmask = src;
2605   float *inmask  = src;
2606   if(source_iter)
2607   {
2608     for(GList *iter = source_iter; iter; iter = g_list_next(iter))
2609     {
2610       dt_dev_pixelpipe_iop_t *module = (dt_dev_pixelpipe_iop_t *)iter->data;
2611       if(module->enabled
2612          && !(module->module->dev->gui_module && module->module->dev->gui_module != module->module
2613               && module->module->dev->gui_module->operation_tags_filter() & module->module->operation_tags()))
2614       {
2615         if(module->module->distort_mask
2616               && !(!strcmp(module->module->op, "finalscale") // hack against pipes not using finalscale
2617                     && module->processed_roi_in.width == 0
2618                     && module->processed_roi_in.height == 0))
2619         {
2620           float *tmp = dt_alloc_align_float((size_t)module->processed_roi_out.width * module->processed_roi_out.height);
2621           if(info) fprintf(stderr," %s %ix%i -> %ix%i,", module->module->op, module->processed_roi_in.width, module->processed_roi_in.height, module->processed_roi_out.width, module->processed_roi_out.height);
2622           module->module->distort_mask(module->module, module, inmask, tmp, &module->processed_roi_in, &module->processed_roi_out);
2623           resmask = tmp;
2624           if(inmask != src) dt_free_align(inmask);
2625           inmask = tmp;
2626         }
2627         else if(!module->module->distort_mask &&
2628                 (module->processed_roi_in.width != module->processed_roi_out.width ||
2629                  module->processed_roi_in.height != module->processed_roi_out.height ||
2630                  module->processed_roi_in.x != module->processed_roi_out.x ||
2631                  module->processed_roi_in.y != module->processed_roi_out.y))
2632               fprintf(stderr, "FIXME: module `%s' changed the roi from %d x %d @ %d / %d to %d x %d | %d / %d but doesn't have "
2633                  "distort_mask() implemented!\n", module->module->op, module->processed_roi_in.width,
2634                  module->processed_roi_in.height, module->processed_roi_in.x, module->processed_roi_in.y,
2635                  module->processed_roi_out.width, module->processed_roi_out.height, module->processed_roi_out.x,
2636                  module->processed_roi_out.y);
2637 
2638         if(module->module == target_module) break;
2639       }
2640     }
2641   }
2642   if(info) fprintf(stderr, " done\n");
2643   return resmask;
2644 }
2645 
2646 // modelines: These editor modelines have been set for all relevant files by tools/update_modelines.sh
2647 // vim: shiftwidth=2 expandtab tabstop=2 cindent
2648 // kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
2649