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