Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
demosaic.c
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2010-2011 Bruce Guenter.
4 Copyright (C) 2010-2016 johannes hanika.
5 Copyright (C) 2011 Antony Dovgal.
6 Copyright (C) 2011 Henrik Andersson.
7 Copyright (C) 2011 Kaminsky Andrey.
8 Copyright (C) 2011 Olivier Tribout.
9 Copyright (C) 2011 Robert Bieber.
10 Copyright (C) 2011 Sergey Pavlov.
11 Copyright (C) 2011-2014, 2016, 2019 Tobias Ellinghaus.
12 Copyright (C) 2011-2012, 2014-2017 Ulrich Pegelow.
13 Copyright (C) 2012, 2015, 2020-2022 Aldric Renaudin.
14 Copyright (C) 2012, 2014-2015 Pascal de Bruijn.
15 Copyright (C) 2012 Richard Wonka.
16 Copyright (C) 2013-2016, 2019 Roman Lebedev.
17 Copyright (C) 2013 Thomas Pryds.
18 Copyright (C) 2014-2017 Dan Torop.
19 Copyright (C) 2015-2016 Pedro Côrte-Real.
20 Copyright (C) 2017-2019 Heiko Bauke.
21 Copyright (C) 2017, 2019 Ingo Liebhardt.
22 Copyright (C) 2017, 2019, 2021 luzpaz.
23 Copyright (C) 2017 Peter Budai.
24 Copyright (C) 2018-2020, 2023-2026 Aurélien PIERRE.
25 Copyright (C) 2018-2019 Edgardo Hoszowski.
26 Copyright (C) 2018 Kelvie Wong.
27 Copyright (C) 2018 Maurizio Paglia.
28 Copyright (C) 2018, 2020-2022 Pascal Obry.
29 Copyright (C) 2018 rawfiner.
30 Copyright (C) 2019 Andreas Schneider.
31 Copyright (C) 2019-2022 Hanno Schwalm.
32 Copyright (C) 2020 Chris Elston.
33 Copyright (C) 2020, 2022 Diederik Ter Rahe.
34 Copyright (C) 2020 Felipe Contreras.
35 Copyright (C) 2020-2021 Hubert Kowalski.
36 Copyright (C) 2020-2021 Ralf Brown.
37 Copyright (C) 2022 Martin Bařinka.
38 Copyright (C) 2022 Philipp Lutz.
39 Copyright (C) 2022 Victor Forsiuk.
40 Copyright (C) 2023 Alynx Zhou.
41 Copyright (C) 2025 Guillaume Stutin.
42
43 darktable is free software: you can redistribute it and/or modify
44 it under the terms of the GNU General Public License as published by
45 the Free Software Foundation, either version 3 of the License, or
46 (at your option) any later version.
47
48 darktable is distributed in the hope that it will be useful,
49 but WITHOUT ANY WARRANTY; without even the implied warranty of
50 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
51 GNU General Public License for more details.
52
53 You should have received a copy of the GNU General Public License
54 along with darktable. If not, see <http://www.gnu.org/licenses/>.
55*/
56
57#ifdef HAVE_CONFIG_H
58#include "config.h"
59#endif
60
61#include "common/darktable.h"
62#include "common/imagebuf.h"
63#include "common/image_cache.h"
65#include "common/math.h"
66#include "common/opencl.h"
67#include "control/control.h"
68#include "develop/blend.h"
69#include "develop/develop.h"
70#include "develop/format.h"
71#include "develop/imageop.h"
73#include "develop/imageop_gui.h"
74#include "develop/masks.h"
76#include "develop/tiling.h"
77
78#include "bauhaus/bauhaus.h"
79#include "common/colorspaces.h"
80#include "control/conf.h"
82#include "common/bspline.h"
83
84#include "gui/gtk.h"
85#include "iop/iop_api.h"
86
87#include <memory.h>
88#include <stdlib.h>
89#include <string.h>
90#include <time.h>
91#include <complex.h>
92#include <glib.h>
93
94#ifdef __GNUC__
95 #define INLINE __inline
96#else
97 #define INLINE inline
98#endif
99
100#define DEMOSAIC_XTRANS 1024 // masks for non-Bayer demosaic ops
101#define DEMOSAIC_DUAL 2048 // masks for dual demosaicing methods
102#define REDUCESIZE 64
103
104#define XTRANS_SNAPPER 3
105#define BAYER_SNAPPER 2
106#define DOWNSAMPLE_GUIDED_SCALES 1
107
109
111{
112 // methods for Bayer images
113 DT_IOP_DEMOSAIC_PPG = 0, // $DESCRIPTION: "PPG"
114 DT_IOP_DEMOSAIC_AMAZE = 1, // $DESCRIPTION: "AMaZE"
115 DT_IOP_DEMOSAIC_VNG4 = 2, // $DESCRIPTION: "VNG4"
116 DT_IOP_DEMOSAIC_RCD = 5, // $DESCRIPTION: "RCD"
117 DT_IOP_DEMOSAIC_LMMSE = 6, // $DESCRIPTION: "LMMSE"
120 DT_IOP_DEMOSAIC_PASSTHROUGH_MONOCHROME = 3, // $DESCRIPTION: "passthrough (monochrome)"
121 DT_IOP_DEMOSAIC_PASSTHROUGH_COLOR = 4, // $DESCRIPTION: "photosite color (debug)"
122 // methods for x-trans images
123 DT_IOP_DEMOSAIC_VNG = DEMOSAIC_XTRANS | 0, // $DESCRIPTION: "VNG"
124 DT_IOP_DEMOSAIC_MARKESTEIJN = DEMOSAIC_XTRANS | 1, // $DESCRIPTION: "Markesteijn 1-pass"
125 DT_IOP_DEMOSAIC_MARKESTEIJN_3 = DEMOSAIC_XTRANS | 2, // $DESCRIPTION: "Markesteijn 3-pass"
126 DT_IOP_DEMOSAIC_FDC = DEMOSAIC_XTRANS | 4, // $DESCRIPTION: "frequency domain chroma"
127 DT_IOP_DEMOSAIC_MARKEST3_VNG = DEMOSAIC_DUAL | DT_IOP_DEMOSAIC_MARKESTEIJN_3, // $DESCRIPTION: "Markesteijn 3-pass + VNG"
128 DT_IOP_DEMOSAIC_PASSTHR_MONOX = DEMOSAIC_XTRANS | 3, // $DESCRIPTION: "passthrough (monochrome)"
129 DT_IOP_DEMOSAIC_PASSTHR_COLORX = DEMOSAIC_XTRANS | 5, // $DESCRIPTION: "photosite color (debug)"
130 DT_IOP_DEMOSAIC_DOWNSAMPLE = 7, // $DESCRIPTION: "downsample"
132
134{
135 DT_IOP_GREEN_EQ_NO = 0, // $DESCRIPTION: "disabled"
136 DT_IOP_GREEN_EQ_LOCAL = 1, // $DESCRIPTION: "local average"
137 DT_IOP_GREEN_EQ_FULL = 2, // $DESCRIPTION: "full average"
138 DT_IOP_GREEN_EQ_BOTH = 3 // $DESCRIPTION: "full and local average"
140
141
143{
144 DEMOSAIC_SMOOTH_OFF = 0, // $DESCRIPTION: "disabled"
145 DEMOSAIC_SMOOTH_1 = 1, // $DESCRIPTION: "once"
146 DEMOSAIC_SMOOTH_2 = 2, // $DESCRIPTION: "twice"
147 DEMOSAIC_SMOOTH_3 = 3, // $DESCRIPTION: "three times"
148 DEMOSAIC_SMOOTH_4 = 4, // $DESCRIPTION: "four times"
149 DEMOSAIC_SMOOTH_5 = 5, // $DESCRIPTION: "five times"
151
153{
154 LMMSE_REFINE_0 = 0, // $DESCRIPTION: "basic"
155 LMMSE_REFINE_1 = 1, // $DESCRIPTION: "median"
156 LMMSE_REFINE_2 = 2, // $DESCRIPTION: "3x median"
157 LMMSE_REFINE_3 = 3, // $DESCRIPTION: "refine & medians"
158 LMMSE_REFINE_4 = 4, // $DESCRIPTION: "2x refine + medians"
160
162{
163 // demosaic pattern
225
226
237
238
239static inline __attribute__((always_inline)) float intp(float a, float b, float c)
240{ // taken from rt code
241 // calculate a * b + (1 - a) * c
242 // following is valid:
243 // intp(a, b+x, c+x) = intp(a, b, c) + x
244 // intp(a, b*x, c*x) = intp(a, b, c) * x
245 return a * (b - c) + c;
246}
247
254
255
257{
258 dt_iop_demosaic_greeneq_t green_eq; // $DEFAULT: DT_IOP_GREEN_EQ_NO $DESCRIPTION: "match greens"
259 float median_thrs; // $MIN: 0.0 $MAX: 1.0 $DEFAULT: 0.0 $DESCRIPTION: "edge threshold"
260 dt_iop_demosaic_smooth_t color_smoothing; // $DEFAULT: DEMOSAIC_SMOOTH_OFF $DESCRIPTION: "color smoothing"
261 dt_iop_demosaic_method_t demosaicing_method; // $DEFAULT: DT_IOP_DEMOSAIC_RCD $DESCRIPTION: "demosaicing method"
262 dt_iop_demosaic_lmmse_t lmmse_refine; // $DEFAULT: LMMSE_REFINE_1 $DESCRIPTION: "LMMSE refine"
263 float dual_thrs; // $MIN: 0.0 $MAX: 1.0 $DEFAULT: 0.20 $DESCRIPTION: "dual threshold"
265
277
278// Implemented on amaze_demosaic_RT.cc
280 const dt_dev_pixelpipe_iop_t *piece,
281 const float *const in,
282 float *out,
283 const dt_iop_roi_t *const roi_in,
284 const dt_iop_roi_t *const roi_out,
285 const uint32_t filters);
286
287
288// Mind the order of includes, there are internal dependencies
289// FIXME: handle all the branching uniformingly
290#include "demosaic/basic.c"
291#include "demosaic/passthrough.c"
292#include "demosaic/rcd.c"
293#include "demosaic/lmmse.c"
294#include "demosaic/ppg.c"
295#include "demosaic/vng.c"
296#include "demosaic/markesteijn.c"
297#include "demosaic/dual.c"
298
299
300const char *name()
301{
302 return _("demosaic");
303}
304
305const char **description(struct dt_iop_module_t *self)
306{
307 return dt_iop_set_description(self, _("reconstruct full RGB pixels from a sensor color filter array reading"),
308 _("mandatory"),
309 _("linear, raw, scene-referred"),
310 _("linear, raw"),
311 _("linear, RGB, scene-referred"));
312}
313
315{
316 return IOP_GROUP_TECHNICAL;
317}
318
323
325{
326 return IOP_CS_RAW;
327}
328
329int legacy_params(dt_iop_module_t *self, const void *const old_params, const int old_version,
330 void *new_params, const int new_version)
331{
332 typedef struct dt_iop_demosaic_params_t dt_iop_demosaic_params_v4_t;
333 typedef struct dt_iop_demosaic_params_v3_t
334 {
336 float median_thrs;
337 uint32_t color_smoothing;
338 dt_iop_demosaic_method_t demosaicing_method;
339 dt_iop_demosaic_lmmse_t lmmse_refine;
340 } dt_iop_demosaic_params_v3_t;
341
342 if(old_version == 3 && new_version == 4)
343 {
344 dt_iop_demosaic_params_v3_t *o = (dt_iop_demosaic_params_v3_t *)old_params;
345 dt_iop_demosaic_params_v4_t *n = (dt_iop_demosaic_params_v4_t *)new_params;
346 memcpy(n, o, sizeof *o);
347 n->dual_thrs = 0.20f;
348 return 0;
349 }
350
351 if(old_version == 2 && new_version == 3)
352 {
355 n->green_eq = o->green_eq;
356 n->median_thrs = o->median_thrs;
357 n->color_smoothing = 0;
358 n->demosaicing_method = DT_IOP_DEMOSAIC_PPG;
359 n->lmmse_refine = LMMSE_REFINE_1;
360 return 0;
361 }
362 return 1;
363}
364
367{
368 default_input_format(self, pipe, piece, dsc);
369 dsc->channels = 1;
371}
372
375{
376 dsc->channels = 4;
377 dsc->datatype = TYPE_FLOAT;
378 dsc->cst = IOP_CS_RGB;
379}
380
381static inline __attribute__((always_inline)) const char* method2string(dt_iop_demosaic_method_t method)
382{
383 const char *string;
384
385 switch(method)
386 {
388 string = "PPG";
389 break;
391 string = "AMaZE";
392 break;
394 string = "VNG4";
395 break;
397 string = "passthrough monochrome";
398 break;
400 string = "photosites";
401 break;
403 string = "RCD";
404 break;
406 string = "LMMSE";
407 break;
409 string = "RCD + VNG4";
410 break;
412 string = "AMaZE + VNG4";
413 break;
415 string = "VNG (xtrans)";
416 break;
418 string = "Markesteijn-1 (XTrans)";
419 break;
421 string = "Markesteijn-3 (XTrans)";
422 break;
424 string = "Markesteijn 3-pass + VNG";
425 break;
427 string = "Frequency Domain Chroma (XTrans)";
428 break;
430 string = "passthrough monochrome (XTrans)";
431 break;
433 string = "photosites (XTrans)";
434 break;
436 string = "downsample";
437 break;
438 default:
439 string = "(unknown method)";
440 }
441 return string;
442}
443
444static inline gboolean _is_downsample_method(const dt_iop_demosaic_method_t method)
445{
446 return method == DT_IOP_DEMOSAIC_DOWNSAMPLE;
447}
448
458static void _downsample_bayer_half_size(float *const out, const float *const in,
459 const dt_iop_roi_t *const roi_out,
460 const dt_iop_roi_t *const roi_in, const uint32_t filters,
461 const gboolean is_4bayer, const double CAM_to_RGB[3][4])
462{
463 __OMP_PARALLEL_FOR__(collapse(2))
464 for(int y = 0; y < roi_out->height; y++)
465 {
466 for(int x = 0; x < roi_out->width; x++)
467 {
468 float *const outc = out + 4 * ((size_t)y * roi_out->width + x);
469 dt_aligned_pixel_t cam = { 0.0f };
470 int samples[4] = { 0 };
471 const int px = MIN(2 * x, roi_in->width - 1);
472 const int py = MIN(2 * y, roi_in->height - 1);
473
474 // Collect the 2x2 source block feeding this output pixel and average only
475 // same-colour photosites together so we do not invent new chroma detail.
476 for(int j = 0; j < 2; j++)
477 {
478 for(int i = 0; i < 2; i++)
479 {
480 const int xx = MIN(px + i, roi_in->width - 1);
481 const int yy = MIN(py + j, roi_in->height - 1);
482 const int c = FC(yy, xx, filters);
483 cam[c] += in[(size_t)yy * roi_in->width + xx];
484 samples[c]++;
485 }
486 }
487
488 for(int c = 0; c < 4; c++)
489 if(samples[c] > 0) cam[c] /= (float)samples[c];
490
491 if(is_4bayer)
492 {
493 for(int c = 0; c < 3; c++)
494 {
495 outc[c] = 0.0f;
496 for(int k = 0; k < 4; k++) outc[c] += CAM_to_RGB[c][k] * cam[k];
497 }
498 }
499 else
500 {
501 outc[0] = cam[RED];
502 outc[1] = cam[GREEN];
503 outc[2] = cam[BLUE];
504 }
505
506 outc[3] = 0.0f;
507 }
508 }
509}
510
520static float _downsample_xtrans_missing_colour(const float *const in, const dt_iop_roi_t *const roi_in,
521 const int px, const int py,
522 const uint8_t (*const xtrans)[6], const int colour)
523{
524 const float cx = px + 0.5f;
525 const float cy = py + 0.5f;
526 const int xmin = MAX(0, px - 3);
527 const int xmax = MIN(roi_in->width - 1, px + 4);
528 const int ymin = MAX(0, py - 3);
529 const int ymax = MIN(roi_in->height - 1, py + 4);
530
531 float quadrant_value[4] = { 0.0f };
532 float quadrant_dist[4] = { INFINITY, INFINITY, INFINITY, INFINITY };
533 int quadrant_x[4] = { 0 };
534 int quadrant_y[4] = { 0 };
535 gboolean quadrant_valid[4] = { FALSE, FALSE, FALSE, FALSE };
536
537 float nearest_value = 0.0f;
538 float nearest_dist = INFINITY;
539
540 // Search the local 7x7 neighbourhood because X-Trans can place the next sample
541 // of a given colour two pixels away from the 2x2 block feeding the output.
542 for(int yy = ymin; yy <= ymax; yy++)
543 {
544 for(int xx = xmin; xx <= xmax; xx++)
545 {
546 if(FCxtrans(yy, xx, roi_in, xtrans) != colour) continue;
547
548 const float dx = xx - cx;
549 const float dy = yy - cy;
550 const float dist2 = dx * dx + dy * dy;
551 if(dist2 < nearest_dist)
552 {
553 nearest_dist = dist2;
554 nearest_value = in[(size_t)yy * roi_in->width + xx];
555 }
556
557 const int quadrant = ((yy > cy) ? 2 : 0) + ((xx > cx) ? 1 : 0);
558 if(dist2 < quadrant_dist[quadrant])
559 {
560 quadrant_dist[quadrant] = dist2;
561 quadrant_value[quadrant] = in[(size_t)yy * roi_in->width + xx];
562 quadrant_x[quadrant] = xx;
563 quadrant_y[quadrant] = yy;
564 quadrant_valid[quadrant] = TRUE;
565 }
566 }
567 }
568
569 if(quadrant_valid[0] && quadrant_valid[1] && quadrant_valid[2] && quadrant_valid[3])
570 {
571 const float x_left = 0.5f * (quadrant_x[0] + quadrant_x[2]);
572 const float x_right = 0.5f * (quadrant_x[1] + quadrant_x[3]);
573 const float y_top = 0.5f * (quadrant_y[0] + quadrant_y[1]);
574 const float y_bottom = 0.5f * (quadrant_y[2] + quadrant_y[3]);
575 const float tx = CLAMP((cx - x_left) / MAX(x_right - x_left, 1e-6f), 0.0f, 1.0f);
576 const float ty = CLAMP((cy - y_top) / MAX(y_bottom - y_top, 1e-6f), 0.0f, 1.0f);
577 const float top = quadrant_value[0] + tx * (quadrant_value[1] - quadrant_value[0]);
578 const float bottom = quadrant_value[2] + tx * (quadrant_value[3] - quadrant_value[2]);
579 return top + ty * (bottom - top);
580 }
581
582 float sum = 0.0f;
583 int count = 0;
584 for(int q = 0; q < 4; q++)
585 {
586 if(!quadrant_valid[q]) continue;
587 sum += quadrant_value[q];
588 count++;
589 }
590
591 return (count > 0) ? sum / (float)count : nearest_value;
592}
593
602static void _downsample_xtrans_half_size(float *const out, const float *const in,
603 const dt_iop_roi_t *const roi_out,
604 const dt_iop_roi_t *const roi_in,
605 const uint8_t (*const xtrans)[6])
606{
607 __OMP_PARALLEL_FOR__(collapse(2))
608 for(int y = 0; y < roi_out->height; y++)
609 {
610 for(int x = 0; x < roi_out->width; x++)
611 {
612 float *const outc = out + 4 * ((size_t)y * roi_out->width + x);
613 dt_aligned_pixel_t rgb = { 0.0f };
614 int samples[3] = { 0 };
615 const int px = MIN(2 * x, roi_in->width - 1);
616 const int py = MIN(2 * y, roi_in->height - 1);
617
618 // Reuse the real X-Trans photosites that already fall inside the source 2x2 block
619 // and only interpolate the colours that the local pattern does not sample there.
620 for(int j = 0; j < 2; j++)
621 {
622 for(int i = 0; i < 2; i++)
623 {
624 const int xx = MIN(px + i, roi_in->width - 1);
625 const int yy = MIN(py + j, roi_in->height - 1);
626 const int c = FCxtrans(yy, xx, roi_in, xtrans);
627 rgb[c] += in[(size_t)yy * roi_in->width + xx];
628 samples[c]++;
629 }
630 }
631
632 for(int c = 0; c < 3; c++)
633 {
634 if(samples[c] > 0)
635 outc[c] = rgb[c] / (float)samples[c];
636 else
637 outc[c] = _downsample_xtrans_missing_colour(in, roi_in, px, py, xtrans, c);
638 }
639
640 outc[3] = 0.0f;
641 }
642 }
643}
644
658static void _downsample_guided_laplacian_fit(const float *const restrict HF,
659 float *const restrict coeff,
660 float *const restrict bias,
661 const size_t width, const size_t height)
662{
663 const float eps = 1e-12f;
664 const dt_aligned_pixel_simd_t zero = dt_simd_set1(0.f);
665 const dt_aligned_pixel_simd_t inv_patch = dt_simd_set1(1.f / 25.f);
667 for(size_t row = 0; row < height; ++row)
668 {
669 const float *const row0 = HF + 4 * ((size_t)CLAMP((int)row - 2, 0, (int)height - 1) * width);
670 const float *const row1 = HF + 4 * ((size_t)CLAMP((int)row - 1, 0, (int)height - 1) * width);
671 const float *const row2 = HF + 4 * (row * width);
672 const float *const row3 = HF + 4 * ((size_t)CLAMP((int)row + 1, 0, (int)height - 1) * width);
673 const float *const row4 = HF + 4 * ((size_t)CLAMP((int)row + 2, 0, (int)height - 1) * width);
674 const float *const rows[BSPLINE_FSIZE] = { row0, row1, row2, row3, row4 };
675 const int max_col = (int)width - 1;
676
677 for(size_t col = 0; col < width; ++col)
678 {
679 dt_aligned_pixel_simd_t sum_rgb = zero;
680 dt_aligned_pixel_simd_t sum_rgb_guide = zero;
681 float sum_guide = 0.f;
682 float sum_guide_sq = 0.f;
683 const int col_offsets[BSPLINE_FSIZE]
684 = { 4 * CLAMP((int)col - 2, 0, max_col),
685 4 * CLAMP((int)col - 1, 0, max_col),
686 4 * (int)col,
687 4 * CLAMP((int)col + 1, 0, max_col),
688 4 * CLAMP((int)col + 2, 0, max_col) };
689
690 // Walk the dense 5x5 neighbourhood once. The 5 clamped column offsets are
691 // hoisted once per output pixel so the inner loop keeps only loads and moment
692 // accumulation for the RGB channels and their shared guide. Keep those loops
693 // as counted loops so GCC does not fully unroll all 25 taps and spill the
694 // intermediate guide terms to the stack.
695#if defined(__GNUC__) && !defined(__clang__)
696#pragma GCC unroll 1
697#endif
698 for(int jj = 0; jj < BSPLINE_FSIZE; ++jj)
699 {
700 const float *const row_ptr = rows[jj];
701#if defined(__GNUC__) && !defined(__clang__)
702#pragma GCC unroll 1
703#endif
704 for(int ii = 0; ii < BSPLINE_FSIZE; ++ii)
705 {
706 const dt_aligned_pixel_simd_t sample = dt_load_simd_aligned(row_ptr + col_offsets[ii]);
707 const float guide = (sample[RED] + sample[GREEN] + sample[BLUE]) / 3.f;
708
709 sum_rgb += sample;
710 sum_guide += guide;
711 sum_guide_sq += guide * guide;
712 sum_rgb_guide += sample * dt_simd_set1(guide);
713 }
714 }
715
716 dt_aligned_pixel_simd_t means = sum_rgb * inv_patch;
717 const float guide_mean = sum_guide * (1.f / 25.f);
718 float variance = sum_guide_sq * (1.f / 25.f) - sqf(guide_mean);
719 dt_aligned_pixel_simd_t covariance = sum_rgb_guide * inv_patch - means * dt_simd_set1(guide_mean);
720 means[ALPHA] = 0.f;
721 covariance[ALPHA] = 0.f;
722
723 if(variance < 0.f) variance = 0.f;
724
725 dt_aligned_pixel_simd_t slope = zero;
726 if(variance > eps) slope = covariance / dt_simd_set1(variance);
727 slope[ALPHA] = 0.f;
728
729 dt_aligned_pixel_simd_t intercept = means - slope * dt_simd_set1(guide_mean);
730 intercept[ALPHA] = 0.f;
731
732 dt_store_simd_aligned(coeff + 4 * (row * width + col), slope);
733 dt_store_simd_aligned(bias + 4 * (row * width + col), intercept);
734 }
735 }
736}
737
747static void _downsample_guided_laplacian_apply(const float *const restrict HF,
748 const float *const restrict coeff,
749 const float *const restrict bias,
750 const float *const restrict LF,
751 float *const restrict reconstructed,
752 const size_t width, const size_t height,
753 const gboolean reset)
754{
756 for(size_t row = 0; row < height; ++row)
757 {
758 for(size_t col = 0; col < width; ++col)
759 {
760 const size_t index = 4 * (row * width + col);
761 const dt_aligned_pixel_simd_t hf = dt_load_simd_aligned(HF + index);
762 const dt_aligned_pixel_simd_t guide = dt_simd_set1((hf[RED] + hf[GREEN] + hf[BLUE]) / 3.f);
763 dt_aligned_pixel_simd_t filtered = (dt_load_simd_aligned(coeff + index) * guide
764 + dt_load_simd_aligned(bias + index))
765 * dt_load_simd_aligned(LF + index);
766
767 if(!reset) filtered += dt_load_simd_aligned(reconstructed + index);
768 filtered[ALPHA] = 0.f;
769 dt_store_simd_aligned(reconstructed + index, filtered);
770 }
771 }
772}
773
788 const size_t width, const size_t height,
789 const int iterations)
790{
791 if(iterations <= 0) return 0;
792
793 const size_t pixels = width * height;
794 float *const restrict LF_even = dt_pixelpipe_cache_alloc_align_float_cache(4 * pixels, 0);
795 float *const restrict LF_odd = dt_pixelpipe_cache_alloc_align_float_cache(4 * pixels, 0);
796 float *const restrict HF = dt_pixelpipe_cache_alloc_align_float_cache(4 * pixels, 0);
797 float *const restrict reconstructed = dt_pixelpipe_cache_alloc_align_float_cache(4 * pixels, 0);
798 float *const restrict coeff = dt_pixelpipe_cache_alloc_align_float_cache(4 * pixels, 0);
799 float *const restrict bias = dt_pixelpipe_cache_alloc_align_float_cache(4 * pixels, 0);
800 float *const restrict coeff_tmp = dt_pixelpipe_cache_alloc_align_float_cache(4 * pixels, 0);
801 size_t padded_size;
802 float *const restrict tempbuf = dt_pixelpipe_cache_alloc_perthread_float(4 * width, &padded_size);
803 const float *restrict residual = out;
804 int err = 0;
805
806 if(IS_NULL_PTR(LF_even) || IS_NULL_PTR(LF_odd) || IS_NULL_PTR(HF) || IS_NULL_PTR(reconstructed) || IS_NULL_PTR(coeff) || IS_NULL_PTR(bias) || IS_NULL_PTR(coeff_tmp) || IS_NULL_PTR(tempbuf))
807 {
808 err = 1;
809 goto cleanup;
810 }
811
812 for(int iteration = 0; iteration < iterations; ++iteration)
813 {
814 residual = out;
815
816 for(int s = 0; s < DOWNSAMPLE_GUIDED_SCALES; ++s)
817 {
818 const int mult = 1 << s;
819 const float *restrict buffer_in;
820 float *restrict buffer_out;
821
822 if(s == 0)
823 {
824 buffer_in = out;
825 buffer_out = LF_odd;
826 }
827 else if(s % 2 != 0)
828 {
829 buffer_in = LF_odd;
830 buffer_out = LF_even;
831 }
832 else
833 {
834 buffer_in = LF_even;
835 buffer_out = LF_odd;
836 }
837
838 decompose_2D_Bspline(buffer_in, HF, buffer_out, width, height, mult, tempbuf, padded_size);
839 // Express the current wavelet band as relative detail over the blur that created it
840 // so the linear RGB model follows local chroma ratios instead of absolute amplitudes.
842 for(size_t row = 0; row < height; ++row)
843 {
844 for(size_t col = 0; col < width; ++col)
845 {
846 const size_t index = 4 * (row * width + col);
847 dt_aligned_pixel_simd_t lf = dt_load_simd_aligned(buffer_out + index);
848 lf[RED] = fmaxf(lf[RED], 1e-8f);
849 lf[GREEN] = fmaxf(lf[GREEN], 1e-8f);
850 lf[BLUE] = fmaxf(lf[BLUE], 1e-8f);
851 lf[ALPHA] = 1.f;
852
853 dt_aligned_pixel_simd_t normalized = dt_load_simd_aligned(HF + index) / lf;
854 normalized[ALPHA] = 0.f;
855 dt_store_simd_aligned(HF + index, normalized);
856 }
857 }
858
860
861 blur_2D_Bspline(coeff, coeff_tmp, tempbuf, width, height, 1, FALSE);
863 blur_2D_Bspline(bias, coeff_tmp, tempbuf, width, height, 1, FALSE);
864 dt_iop_image_copy_by_size(bias, coeff_tmp, width, height, 4);
865
866 _downsample_guided_laplacian_apply(HF, coeff, bias, buffer_out, reconstructed,
867 width, height, s == 0);
868 residual = buffer_out;
869 }
870
871 const gboolean last_iteration = (iteration == iterations - 1);
873 for(size_t row = 0; row < height; ++row)
874 {
875 for(size_t col = 0; col < width; ++col)
876 {
877 const size_t index = 4 * (row * width + col);
878 dt_aligned_pixel_simd_t pixel
879 = dt_simd_max_zero(dt_load_simd_aligned(reconstructed + index)
880 + dt_load_simd_aligned(residual + index));
881 pixel[ALPHA] = 0.f;
882
883 if(last_iteration)
884 dt_store_simd_nontemporal(out + index, pixel);
885 else
886 dt_store_simd_aligned(out + index, pixel);
887 }
888 }
889 }
890 dt_omploop_sfence(); // ensure the final nontemporal writeback completes before the caller reads out
891
892cleanup:
897 dt_pixelpipe_cache_free_align(reconstructed);
901 return err;
902}
903
904
905void distort_mask(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe, struct dt_dev_pixelpipe_iop_t *piece,
906 const float *const in, float *const out, const dt_iop_roi_t *const roi_in,
907 const dt_iop_roi_t *const roi_out)
908{
909 (void)pipe;
911 dt_interpolation_resample_roi_1c(itor, out, roi_out, in, roi_in);
912}
913
914void modify_roi_out(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe,
915 struct dt_dev_pixelpipe_iop_t *piece, dt_iop_roi_t *roi_out,
916 const dt_iop_roi_t *const roi_in)
917{
918 *roi_out = *roi_in;
919
922 {
923 roi_out->width = (roi_in->width + 1) / 2;
924 roi_out->height = (roi_in->height + 1) / 2;
925 }
926
927 // snap to start of mosaic block:
928 roi_out->x = 0; // MAX(0, roi_out->x & ~1);
929 roi_out->y = 0; // MAX(0, roi_out->y & ~1);
930}
931
932// which roi input is needed to process to this output?
933// roi_out is unchanged, full buffer in is full buffer out.
934// see ../../doc/resizing-scaling.md for details
935void modify_roi_in(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe,
936 struct dt_dev_pixelpipe_iop_t *piece,
937 const dt_iop_roi_t *roi_out, dt_iop_roi_t *roi_in)
938{
939 // this op is disabled for filters == 0
940 *roi_in = *roi_out;
941
943 const int method = data->demosaicing_method;
944 const gboolean passthrough = (method == DT_IOP_DEMOSAIC_PASSTHROUGH_MONOCHROME) ||
946 const gboolean downsample = _is_downsample_method(method);
947
948 if(downsample)
949 {
950 roi_in->x *= 2;
951 roi_in->y *= 2;
952 roi_in->width *= 2;
953 roi_in->height *= 2;
954
955 // Half-size mode maps each output pixel to one 2x2 raw block, so keep the exact
956 // 2x addressing and clamp only the tail block against the available input buffer.
957 roi_in->x = CLAMP(roi_in->x, 0, MAX(0, piece->buf_in.width - 1));
958 roi_in->y = CLAMP(roi_in->y, 0, MAX(0, piece->buf_in.height - 1));
959 roi_in->width = CLAMP(roi_in->width, 1, piece->buf_in.width - roi_in->x);
960 roi_in->height = CLAMP(roi_in->height, 1, piece->buf_in.height - roi_in->y);
961 return;
962 }
963
964 // set position to closest sensor pattern snap
965 if(!passthrough)
966 {
967 // ROI planning happens during history -> pipeline resync, before recursion has initialized piece->dsc_in.
968 // The snap period must therefore come from the immutable RAW input descriptor attached to the image.
969 const int aligner = (piece->module->dev->image_storage.dsc.filters != 9u) ? BAYER_SNAPPER : XTRANS_SNAPPER;
970 const int dx = roi_in->x % aligner;
971 const int dy = roi_in->y % aligner;
972 const int shift_x = (dx > aligner / 2) ? aligner - dx : -dx;
973 const int shift_y = (dy > aligner / 2) ? aligner - dy : -dy;
974
975 roi_in->x = MAX(0, roi_in->x + shift_x);
976 roi_in->y = MAX(0, roi_in->y + shift_y);
977 }
978}
979
980
982int process(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece,
983 const void *const i, void *const o)
984{
985 const dt_iop_roi_t *const roi_in = &piece->roi_in;
986 const dt_iop_roi_t *const roi_out = &piece->roi_out;
987 const dt_image_t *img = &self->dev->image_storage;
988 const float threshold = 0.0001f * img->exif_iso;
989 dt_times_t start_time = { 0 }, end_time = { 0 };
990
991 dt_iop_roi_t roi = *roi_in;
992 dt_iop_roi_t roo = *roi_out;
993 roo.x = roo.y = 0;
994 // roi_out->scale = global scale: (iscale == 1.0, always when demosaic is on)
995 const gboolean info = ((darktable.unmuted & (DT_DEBUG_DEMOSAIC | DT_DEBUG_PERF))
996 && (pipe->type == DT_DEV_PIXELPIPE_FULL));
997
998 const uint8_t(*const xtrans)[6] = (const uint8_t(*const)[6])piece->dsc_in.xtrans;
999
1002
1003 int demosaicing_method = data->demosaicing_method;
1004
1005 gboolean showmask = FALSE;
1006 if(self->dev->gui_attached && pipe->type == DT_DEV_PIXELPIPE_FULL)
1007 {
1009 if(g) showmask = (g->visual_mask);
1010 // take care of passthru modes
1012 demosaicing_method = (piece->dsc_in.filters != 9u) ? DT_IOP_DEMOSAIC_RCD : DT_IOP_DEMOSAIC_MARKESTEIJN;
1014 demosaicing_method = DT_IOP_DEMOSAIC_PASSTHROUGH_MONOCHROME;
1015 }
1016
1017 const float *const pixels = (float *)i;
1018
1019 // Full demosaic and then scaling if needed
1020 if(info) dt_get_times(&start_time);
1021
1022 if(_is_downsample_method(demosaicing_method))
1023 {
1024 if(piece->dsc_in.filters == 9u)
1025 _downsample_xtrans_half_size(o, pixels, &roo, &roi, xtrans);
1026 else
1027 _downsample_bayer_half_size(o, pixels, &roo, &roi, piece->dsc_in.filters,
1028 img->flags & DT_IMAGE_4BAYER, data->CAM_to_RGB);
1029
1031 }
1032 else if(demosaicing_method == DT_IOP_DEMOSAIC_PASSTHROUGH_MONOCHROME)
1033 {
1034 passthrough_monochrome(o, pixels, &roo, &roi);
1035 }
1036 else if(demosaicing_method == DT_IOP_DEMOSAIC_PASSTHROUGH_COLOR)
1037 {
1038 passthrough_color(o, pixels, &roo, &roi, piece->dsc_in.filters, xtrans);
1039 }
1040 else if(piece->dsc_in.filters == 9u)
1041 {
1042 const int passes = (demosaicing_method == DT_IOP_DEMOSAIC_MARKESTEIJN) ? 1 : 3;
1043 if(demosaicing_method == DT_IOP_DEMOSAIC_MARKEST3_VNG)
1044 xtrans_markesteijn_interpolate(o, pixels, &roo, &roi, xtrans, passes);
1045 else if(demosaicing_method == DT_IOP_DEMOSAIC_FDC)
1046 xtrans_fdc_interpolate(self, o, pixels, &roo, &roi, xtrans);
1047 else if(demosaicing_method >= DT_IOP_DEMOSAIC_MARKESTEIJN)
1048 xtrans_markesteijn_interpolate(o, pixels, &roo, &roi, xtrans, passes);
1049 else
1050 if(vng_interpolate(o, pixels, &roo, &roi, piece->dsc_in.filters, xtrans, FALSE))
1051 return 1;
1052 }
1053 else
1054 {
1055 float *in = (float *)pixels;
1056 float *aux;
1057
1058 if(!(img->flags & DT_IMAGE_4BAYER) && data->green_eq != DT_IOP_GREEN_EQ_NO)
1059 {
1060 in = dt_pixelpipe_cache_alloc_align_float((size_t)roi_in->height * roi_in->width, pipe);
1061 if(!IS_NULL_PTR(in))
1062 {
1063 switch(data->green_eq)
1064 {
1066 green_equilibration_favg(in, pixels, roi_in->width, roi_in->height, piece->dsc_in.filters,
1067 roi_in->x, roi_in->y);
1068 break;
1070 green_equilibration_lavg(in, pixels, roi_in->width, roi_in->height, piece->dsc_in.filters,
1071 roi_in->x, roi_in->y, threshold);
1072 break;
1074 aux = dt_pixelpipe_cache_alloc_align_float((size_t)roi_in->height * roi_in->width, pipe);
1075 if(IS_NULL_PTR(aux))
1076 {
1078 return 1;
1079 }
1080 green_equilibration_favg(aux, pixels, roi_in->width, roi_in->height, piece->dsc_in.filters,
1081 roi_in->x, roi_in->y);
1082 green_equilibration_lavg(in, aux, roi_in->width, roi_in->height, piece->dsc_in.filters, roi_in->x,
1083 roi_in->y, threshold);
1085 break;
1086 }
1087 }
1088 else
1089 {
1090 return 1;
1091 }
1092 }
1093
1094 if(demosaicing_method == DT_IOP_DEMOSAIC_VNG4 || (img->flags & DT_IMAGE_4BAYER))
1095 {
1096 if(vng_interpolate(o, in, &roo, &roi, piece->dsc_in.filters, xtrans, FALSE))
1097 return 1;
1098 if(img->flags & DT_IMAGE_4BAYER)
1099 {
1101 dt_aligned_pixel_t processed_maximum = { piece->dsc_in.processed_maximum[0], piece->dsc_in.processed_maximum[1],
1102 piece->dsc_in.processed_maximum[2], 0.0f };
1103 dt_colorspaces_cygm_to_rgb(processed_maximum, 1, data->CAM_to_RGB);
1104 }
1105 }
1106 else if((demosaicing_method & ~DEMOSAIC_DUAL) == DT_IOP_DEMOSAIC_RCD)
1107 {
1108 rcd_demosaic(piece, o, in, &roo, &roi, piece->dsc_in.filters);
1109 }
1110 else if(demosaicing_method == DT_IOP_DEMOSAIC_LMMSE)
1111 {
1113 {
1117 {
1120 gd->lmmse_gamma_in = NULL;
1121 gd->lmmse_gamma_out = NULL;
1122 if(!(img->flags & DT_IMAGE_4BAYER) && data->green_eq != DT_IOP_GREEN_EQ_NO)
1124 return 1;
1125 }
1126#ifdef _OPENMP
1127 #pragma omp for
1128#endif
1129 for(int j = 0; j < 65536; j++)
1130 {
1131 const double x = (double)j / 65535.0;
1132 gd->lmmse_gamma_in[j] = (x <= 0.001867) ? x * 17.0 : 1.044445 * exp(log(x) / 2.4) - 0.044445;
1133 gd->lmmse_gamma_out[j] = (x <= 0.031746) ? x / 17.0 : exp(log((x + 0.044445) / 1.044445) * 2.4);
1134 }
1135 }
1136 lmmse_demosaic(piece, o, in, &roo, &roi, piece->dsc_in.filters, data->lmmse_refine, gd->lmmse_gamma_in, gd->lmmse_gamma_out);
1137 }
1138 else if((demosaicing_method & ~DEMOSAIC_DUAL) != DT_IOP_DEMOSAIC_AMAZE)
1139 {
1140 if(demosaic_ppg(o, in, &roo, &roi, piece->dsc_in.filters, data->median_thrs))
1141 {
1142 if(!(img->flags & DT_IMAGE_4BAYER) && data->green_eq != DT_IOP_GREEN_EQ_NO)
1144 return 1;
1145 }
1146 } // wanted ppg or zoomed out a lot and quality is limited to 1
1147 else
1148 amaze_demosaic_RT(piece, in, o, &roi, &roo, piece->dsc_in.filters);
1149
1150 if(!(img->flags & DT_IMAGE_4BAYER) && data->green_eq != DT_IOP_GREEN_EQ_NO)
1152 }
1153
1154 if(info)
1155 {
1156 const float mpixels = (roo.width * roo.height) / 1.0e6;
1157 dt_get_times(&end_time);
1158 const float tclock = end_time.clock - start_time.clock;
1159 const float uclock = end_time.user - start_time.user;
1160 fprintf(stderr," [demosaic] process CPU `%s' did %.2fmpix, %.4f secs (%.4f CPU), %.2f pix/us\n",
1161 method2string(demosaicing_method & ~DEMOSAIC_DUAL), mpixels, tclock, uclock, mpixels / tclock);
1162 }
1163
1164 if((demosaicing_method & DEMOSAIC_DUAL))
1165 {
1166 if(dual_demosaic(pipe, piece, o, pixels, &roo, &roi, piece->dsc_in.filters, xtrans, showmask, data->dual_thrs))
1167 return 1;
1168 }
1169
1170 if(data->color_smoothing && !_is_downsample_method(demosaicing_method))
1171 color_smoothing(o, roi_out, data->color_smoothing);
1172
1173 return 0;
1174}
1175
1176#ifdef HAVE_OPENCL
1177static int process_default_cl(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe,
1178 const dt_dev_pixelpipe_iop_t *piece, cl_mem dev_in,
1179 cl_mem dev_out, const dt_iop_roi_t *const roi_in,
1180 const dt_iop_roi_t *const roi_out, const int demosaicing_method)
1181{
1184
1185 const int devid = pipe->devid;
1186
1187 cl_mem dev_aux = NULL;
1188 cl_mem dev_tmp = NULL;
1189 cl_mem dev_med = NULL;
1190 cl_mem dev_green_eq = NULL;
1191 cl_int err = -999;
1192
1193 int width = roi_out->width;
1194 int height = roi_out->height;
1195
1196 // green equilibration
1197 if(data->green_eq != DT_IOP_GREEN_EQ_NO)
1198 {
1199 dev_green_eq = dt_opencl_alloc_device(devid, roi_in->width, roi_in->height, sizeof(float));
1200 if(IS_NULL_PTR(dev_green_eq)) goto error;
1201
1202 if(!green_equilibration_cl(self, pipe, piece, dev_in, dev_green_eq, roi_in))
1203 goto error;
1204
1205 dev_in = dev_green_eq;
1206 }
1207
1208 // need to reserve scaled auxiliary buffer or use dev_out
1209 dev_aux = dev_out;
1210
1211 if(demosaicing_method == DT_IOP_DEMOSAIC_PASSTHROUGH_MONOCHROME)
1212 {
1213 size_t sizes[3] = { ROUNDUPDWD(width, devid), ROUNDUPDHT(height, devid), 1 };
1214 dt_opencl_set_kernel_arg(devid, gd->kernel_passthrough_monochrome, 0, sizeof(cl_mem), &dev_in);
1215 dt_opencl_set_kernel_arg(devid, gd->kernel_passthrough_monochrome, 1, sizeof(cl_mem), &dev_aux);
1216 dt_opencl_set_kernel_arg(devid, gd->kernel_passthrough_monochrome, 2, sizeof(int), &width);
1219 if(err != CL_SUCCESS) goto error;
1220 }
1221 else if(demosaicing_method == DT_IOP_DEMOSAIC_PASSTHROUGH_COLOR)
1222 {
1223 size_t sizes[3] = { ROUNDUPDWD(width, devid), ROUNDUPDHT(height, devid), 1 };
1224 dt_opencl_set_kernel_arg(devid, gd->kernel_passthrough_color, 0, sizeof(cl_mem), &dev_in);
1225 dt_opencl_set_kernel_arg(devid, gd->kernel_passthrough_color, 1, sizeof(cl_mem), &dev_aux);
1226 dt_opencl_set_kernel_arg(devid, gd->kernel_passthrough_color, 2, sizeof(int), &width);
1227 dt_opencl_set_kernel_arg(devid, gd->kernel_passthrough_color, 3, sizeof(int), &height);
1228 dt_opencl_set_kernel_arg(devid, gd->kernel_passthrough_color, 4, sizeof(int), (void *)&roi_in->x);
1229 dt_opencl_set_kernel_arg(devid, gd->kernel_passthrough_color, 5, sizeof(int), (void *)&roi_in->y);
1230 dt_opencl_set_kernel_arg(devid, gd->kernel_passthrough_color, 6, sizeof(uint32_t), (void *)&piece->dsc_in.filters);
1231
1233 if(err != CL_SUCCESS) goto error;
1234 }
1235 else if(demosaicing_method == DT_IOP_DEMOSAIC_PPG)
1236 {
1237 dev_tmp = dt_opencl_alloc_device(devid, roi_in->width, roi_in->height, sizeof(float) * 4);
1238 if(IS_NULL_PTR(dev_tmp)) goto error;
1239
1240 {
1241 const int myborder = 3;
1242 // manage borders
1243 size_t sizes[3] = { ROUNDUPDWD(width, devid), ROUNDUPDHT(height, devid), 1 };
1244 dt_opencl_set_kernel_arg(devid, gd->kernel_border_interpolate, 0, sizeof(cl_mem), &dev_in);
1245 dt_opencl_set_kernel_arg(devid, gd->kernel_border_interpolate, 1, sizeof(cl_mem), &dev_tmp);
1246 dt_opencl_set_kernel_arg(devid, gd->kernel_border_interpolate, 2, sizeof(int), (void *)&width);
1247 dt_opencl_set_kernel_arg(devid, gd->kernel_border_interpolate, 3, sizeof(int), (void *)&height);
1248 dt_opencl_set_kernel_arg(devid, gd->kernel_border_interpolate, 4, sizeof(uint32_t), (void *)&piece->dsc_in.filters);
1249 dt_opencl_set_kernel_arg(devid, gd->kernel_border_interpolate, 5, sizeof(int), (void *)&myborder);
1251 if(err != CL_SUCCESS) goto error;
1252 }
1253
1254 if(data->median_thrs > 0.0f)
1255 {
1256 dev_med = dt_opencl_alloc_device(devid, roi_in->width, roi_in->height, sizeof(float) * 4);
1257 if(IS_NULL_PTR(dev_med)) goto error;
1258
1260 = (dt_opencl_local_buffer_t){ .xoffset = 2*2, .xfactor = 1, .yoffset = 2*2, .yfactor = 1,
1261 .cellsize = 1 * sizeof(float), .overhead = 0,
1262 .sizex = 1 << 8, .sizey = 1 << 8 };
1263
1264 if(!dt_opencl_local_buffer_opt(devid, gd->kernel_pre_median, &locopt))
1265 goto error;
1266
1267 size_t sizes[3] = { ROUNDUP(width, locopt.sizex), ROUNDUP(height, locopt.sizey), 1 };
1268 size_t local[3] = { locopt.sizex, locopt.sizey, 1 };
1269 dt_opencl_set_kernel_arg(devid, gd->kernel_pre_median, 0, sizeof(cl_mem), &dev_in);
1270 dt_opencl_set_kernel_arg(devid, gd->kernel_pre_median, 1, sizeof(cl_mem), &dev_med);
1271 dt_opencl_set_kernel_arg(devid, gd->kernel_pre_median, 2, sizeof(int), &width);
1272 dt_opencl_set_kernel_arg(devid, gd->kernel_pre_median, 3, sizeof(int), &height);
1273 dt_opencl_set_kernel_arg(devid, gd->kernel_pre_median, 4, sizeof(uint32_t),
1274 (void *)&piece->dsc_in.filters);
1275 dt_opencl_set_kernel_arg(devid, gd->kernel_pre_median, 5, sizeof(float), (void *)&data->median_thrs);
1277 sizeof(float) * (locopt.sizex + 4) * (locopt.sizey + 4), NULL);
1278 err = dt_opencl_enqueue_kernel_2d_with_local(devid, gd->kernel_pre_median, sizes, local);
1279 if(err != CL_SUCCESS) goto error;
1280 dev_in = dev_aux;
1281 }
1282 else
1283 dev_med = dev_in;
1284
1285 {
1287 = (dt_opencl_local_buffer_t){ .xoffset = 2*3, .xfactor = 1, .yoffset = 2*3, .yfactor = 1,
1288 .cellsize = sizeof(float) * 1, .overhead = 0,
1289 .sizex = 1 << 8, .sizey = 1 << 8 };
1290
1291 if(!dt_opencl_local_buffer_opt(devid, gd->kernel_ppg_green, &locopt))
1292 goto error;
1293
1294 size_t sizes[3] = { ROUNDUP(width, locopt.sizex), ROUNDUP(height, locopt.sizey), 1 };
1295 size_t local[3] = { locopt.sizex, locopt.sizey, 1 };
1296 dt_opencl_set_kernel_arg(devid, gd->kernel_ppg_green, 0, sizeof(cl_mem), &dev_med);
1297 dt_opencl_set_kernel_arg(devid, gd->kernel_ppg_green, 1, sizeof(cl_mem), &dev_tmp);
1298 dt_opencl_set_kernel_arg(devid, gd->kernel_ppg_green, 2, sizeof(int), &width);
1299 dt_opencl_set_kernel_arg(devid, gd->kernel_ppg_green, 3, sizeof(int), &height);
1300 dt_opencl_set_kernel_arg(devid, gd->kernel_ppg_green, 4, sizeof(uint32_t),
1301 (void *)&piece->dsc_in.filters);
1303 sizeof(float) * (locopt.sizex + 2*3) * (locopt.sizey + 2*3), NULL);
1304
1305 err = dt_opencl_enqueue_kernel_2d_with_local(devid, gd->kernel_ppg_green, sizes, local);
1306 if(err != CL_SUCCESS) goto error;
1307 }
1308
1309 {
1311 = (dt_opencl_local_buffer_t){ .xoffset = 2*1, .xfactor = 1, .yoffset = 2*1, .yfactor = 1,
1312 .cellsize = 4 * sizeof(float), .overhead = 0,
1313 .sizex = 1 << 8, .sizey = 1 << 8 };
1314
1315 if(!dt_opencl_local_buffer_opt(devid, gd->kernel_ppg_redblue, &locopt))
1316 goto error;
1317
1318 size_t sizes[3] = { ROUNDUP(width, locopt.sizex), ROUNDUP(height, locopt.sizey), 1 };
1319 size_t local[3] = { locopt.sizex, locopt.sizey, 1 };
1320 dt_opencl_set_kernel_arg(devid, gd->kernel_ppg_redblue, 0, sizeof(cl_mem), &dev_tmp);
1321 dt_opencl_set_kernel_arg(devid, gd->kernel_ppg_redblue, 1, sizeof(cl_mem), &dev_aux);
1322 dt_opencl_set_kernel_arg(devid, gd->kernel_ppg_redblue, 2, sizeof(int), &width);
1323 dt_opencl_set_kernel_arg(devid, gd->kernel_ppg_redblue, 3, sizeof(int), &height);
1324 dt_opencl_set_kernel_arg(devid, gd->kernel_ppg_redblue, 4, sizeof(uint32_t),
1325 (void *)&piece->dsc_in.filters);
1327 sizeof(float) * 4 * (locopt.sizex + 2) * (locopt.sizey + 2), NULL);
1328
1329 err = dt_opencl_enqueue_kernel_2d_with_local(devid, gd->kernel_ppg_redblue, sizes, local);
1330 if(err != CL_SUCCESS) goto error;
1331 }
1332 }
1333
1334 if(dev_aux != dev_out) dt_opencl_release_mem_object(dev_aux);
1335 if(dev_med != dev_in) dt_opencl_release_mem_object(dev_med);
1336 dt_opencl_release_mem_object(dev_green_eq);
1338 dev_aux = dev_green_eq = dev_tmp = dev_med = NULL;
1339
1340 // color smoothing
1341 if(data->color_smoothing)
1342 {
1343 if(!color_smoothing_cl(self, pipe, piece, dev_out, dev_out, roi_out, data->color_smoothing))
1344 goto error;
1345 }
1346
1347 return TRUE;
1348
1349error:
1350 if(dev_aux != dev_out) dt_opencl_release_mem_object(dev_aux);
1351 if(dev_med != dev_in) dt_opencl_release_mem_object(dev_med);
1352 dt_opencl_release_mem_object(dev_green_eq);
1354 dt_print(DT_DEBUG_OPENCL, "[opencl_demosaic] couldn't enqueue kernel! %d\n", err);
1355 return FALSE;
1356}
1357
1359 const dt_dev_pixelpipe_t *pipe,
1360 cl_mem dev_out,
1361 const dt_iop_roi_t *const roi_out,
1362 const int iterations)
1363{
1364 if(iterations <= 0) return TRUE;
1365
1367 const int devid = pipe->devid;
1368 const int width = roi_out->width;
1369 const int height = roi_out->height;
1370 const int clip_negatives = 1;
1371 const int keep_signed = 0;
1372 const int dense_mult = 1;
1373 size_t sizes[] = { ROUNDUPDWD(width, devid), ROUNDUPDHT(height, devid), 1 };
1374
1375 cl_mem LF_even = NULL;
1376 cl_mem LF_odd = NULL;
1377 cl_mem temp = NULL;
1378 cl_mem coeff = NULL;
1379 cl_mem bias = NULL;
1380 cl_mem coeff_tmp = NULL;
1381 cl_mem reconstructed_a = NULL;
1382 cl_mem reconstructed_b = NULL;
1383 cl_mem residual = NULL;
1384 cl_mem reconstructed_read = NULL;
1385 cl_mem reconstructed_write = NULL;
1386 cl_mem reconstructed_final = NULL;
1387 cl_int err = DT_OPENCL_DEFAULT_ERROR;
1388
1389 LF_even = dt_opencl_alloc_device(devid, width, height, sizeof(float) * 4);
1390 LF_odd = dt_opencl_alloc_device(devid, width, height, sizeof(float) * 4);
1391 temp = dt_opencl_alloc_device(devid, width, height, sizeof(float) * 4);
1392 coeff = dt_opencl_alloc_device(devid, width, height, sizeof(float) * 4);
1393 bias = dt_opencl_alloc_device(devid, width, height, sizeof(float) * 4);
1394 coeff_tmp = dt_opencl_alloc_device(devid, width, height, sizeof(float) * 4);
1395 reconstructed_a = dt_opencl_alloc_device(devid, width, height, sizeof(float) * 4);
1396 reconstructed_b = dt_opencl_alloc_device(devid, width, height, sizeof(float) * 4);
1397 if(IS_NULL_PTR(LF_even) || IS_NULL_PTR(LF_odd) || IS_NULL_PTR(temp) || IS_NULL_PTR(coeff) || IS_NULL_PTR(bias) || IS_NULL_PTR(coeff_tmp)
1398 || IS_NULL_PTR(reconstructed_a) || IS_NULL_PTR(reconstructed_b))
1399 goto error;
1400
1401 for(int iteration = 0; iteration < iterations; ++iteration)
1402 {
1403 reconstructed_read = reconstructed_a;
1404 reconstructed_write = reconstructed_b;
1405 reconstructed_final = NULL;
1406 residual = dev_out;
1407
1408 for(int s = 0; s < DOWNSAMPLE_GUIDED_SCALES; ++s)
1409 {
1410 const int mult = 1 << s;
1411 const int first_scale = (s == 0);
1412 cl_mem buffer_in;
1413 cl_mem buffer_out;
1414
1415 if(s == 0)
1416 {
1417 buffer_in = dev_out;
1418 buffer_out = LF_odd;
1419 }
1420 else if(s % 2 != 0)
1421 {
1422 buffer_in = LF_odd;
1423 buffer_out = LF_even;
1424 }
1425 else
1426 {
1427 buffer_in = LF_even;
1428 buffer_out = LF_odd;
1429 }
1430
1431 int hblocksize;
1432 dt_opencl_local_buffer_t hlocopt = (dt_opencl_local_buffer_t){ .xoffset = 2 * mult, .xfactor = 1,
1433 .yoffset = 0, .yfactor = 1,
1434 .cellsize = 4 * sizeof(float), .overhead = 0,
1435 .sizex = 1 << 16, .sizey = 1 };
1437 hblocksize = hlocopt.sizex;
1438 else
1439 hblocksize = 1;
1440
1441 if(hblocksize > 1)
1442 {
1443 const size_t horizontal_sizes[3] = { ROUNDUP(width, hblocksize), ROUNDUPDHT(height, devid), 1 };
1444 const size_t horizontal_local[3] = { hblocksize, 1, 1 };
1445 dt_opencl_set_kernel_arg(devid, gd->kernel_bspline_horizontal_local, 0, sizeof(cl_mem), &buffer_in);
1446 dt_opencl_set_kernel_arg(devid, gd->kernel_bspline_horizontal_local, 1, sizeof(cl_mem), &temp);
1449 dt_opencl_set_kernel_arg(devid, gd->kernel_bspline_horizontal_local, 4, sizeof(int), &mult);
1450 dt_opencl_set_kernel_arg(devid, gd->kernel_bspline_horizontal_local, 5, sizeof(int), &clip_negatives);
1452 (hblocksize + 4 * mult) * 4 * sizeof(float), NULL);
1454 horizontal_sizes, horizontal_local);
1455 }
1456 else
1457 {
1458 dt_opencl_set_kernel_arg(devid, gd->kernel_bspline_horizontal, 0, sizeof(cl_mem), &buffer_in);
1459 dt_opencl_set_kernel_arg(devid, gd->kernel_bspline_horizontal, 1, sizeof(cl_mem), &temp);
1460 dt_opencl_set_kernel_arg(devid, gd->kernel_bspline_horizontal, 2, sizeof(int), &width);
1461 dt_opencl_set_kernel_arg(devid, gd->kernel_bspline_horizontal, 3, sizeof(int), &height);
1462 dt_opencl_set_kernel_arg(devid, gd->kernel_bspline_horizontal, 4, sizeof(int), &mult);
1463 dt_opencl_set_kernel_arg(devid, gd->kernel_bspline_horizontal, 5, sizeof(int), &clip_negatives);
1465 }
1466 if(err != CL_SUCCESS) goto error;
1467
1468 int vblocksize;
1469 dt_opencl_local_buffer_t vlocopt = (dt_opencl_local_buffer_t){ .xoffset = 0, .xfactor = 1,
1470 .yoffset = 2 * mult, .yfactor = 1,
1471 .cellsize = 4 * sizeof(float), .overhead = 0,
1472 .sizex = 1, .sizey = 1 << 16 };
1474 vblocksize = vlocopt.sizey;
1475 else
1476 vblocksize = 1;
1477
1478 if(vblocksize > 1)
1479 {
1480 const size_t vertical_sizes[3] = { ROUNDUPDWD(width, devid), ROUNDUP(height, vblocksize), 1 };
1481 const size_t vertical_local[3] = { 1, vblocksize, 1 };
1482 dt_opencl_set_kernel_arg(devid, gd->kernel_bspline_vertical_local, 0, sizeof(cl_mem), &temp);
1483 dt_opencl_set_kernel_arg(devid, gd->kernel_bspline_vertical_local, 1, sizeof(cl_mem), &buffer_out);
1484 dt_opencl_set_kernel_arg(devid, gd->kernel_bspline_vertical_local, 2, sizeof(int), &width);
1486 dt_opencl_set_kernel_arg(devid, gd->kernel_bspline_vertical_local, 4, sizeof(int), &mult);
1487 dt_opencl_set_kernel_arg(devid, gd->kernel_bspline_vertical_local, 5, sizeof(int), &clip_negatives);
1489 (vblocksize + 4 * mult) * 4 * sizeof(float), NULL);
1491 vertical_sizes, vertical_local);
1492 }
1493 else
1494 {
1495 dt_opencl_set_kernel_arg(devid, gd->kernel_bspline_vertical, 0, sizeof(cl_mem), &temp);
1496 dt_opencl_set_kernel_arg(devid, gd->kernel_bspline_vertical, 1, sizeof(cl_mem), &buffer_out);
1497 dt_opencl_set_kernel_arg(devid, gd->kernel_bspline_vertical, 2, sizeof(int), &width);
1498 dt_opencl_set_kernel_arg(devid, gd->kernel_bspline_vertical, 3, sizeof(int), &height);
1499 dt_opencl_set_kernel_arg(devid, gd->kernel_bspline_vertical, 4, sizeof(int), &mult);
1500 dt_opencl_set_kernel_arg(devid, gd->kernel_bspline_vertical, 5, sizeof(int), &clip_negatives);
1502 }
1503 if(err != CL_SUCCESS) goto error;
1504
1505 dt_opencl_set_kernel_arg(devid, gd->kernel_guided_laplacian_normalize, 0, sizeof(cl_mem), &buffer_in);
1506 dt_opencl_set_kernel_arg(devid, gd->kernel_guided_laplacian_normalize, 1, sizeof(cl_mem), &buffer_out);
1507 dt_opencl_set_kernel_arg(devid, gd->kernel_guided_laplacian_normalize, 2, sizeof(cl_mem), &temp);
1511 if(err != CL_SUCCESS) goto error;
1512
1513 dt_opencl_set_kernel_arg(devid, gd->kernel_guided_laplacian_coefficients, 0, sizeof(cl_mem), &temp);
1515 dt_opencl_set_kernel_arg(devid, gd->kernel_guided_laplacian_coefficients, 2, sizeof(cl_mem), &bias);
1519 if(err != CL_SUCCESS) goto error;
1520
1521 dt_opencl_set_kernel_arg(devid, gd->kernel_bspline_horizontal, 0, sizeof(cl_mem), &coeff);
1522 dt_opencl_set_kernel_arg(devid, gd->kernel_bspline_horizontal, 1, sizeof(cl_mem), &coeff_tmp);
1523 dt_opencl_set_kernel_arg(devid, gd->kernel_bspline_horizontal, 2, sizeof(int), &width);
1524 dt_opencl_set_kernel_arg(devid, gd->kernel_bspline_horizontal, 3, sizeof(int), &height);
1525 dt_opencl_set_kernel_arg(devid, gd->kernel_bspline_horizontal, 4, sizeof(int), &dense_mult);
1526 dt_opencl_set_kernel_arg(devid, gd->kernel_bspline_horizontal, 5, sizeof(int), &keep_signed);
1528 if(err != CL_SUCCESS) goto error;
1529
1530 dt_opencl_set_kernel_arg(devid, gd->kernel_bspline_vertical, 0, sizeof(cl_mem), &coeff_tmp);
1531 dt_opencl_set_kernel_arg(devid, gd->kernel_bspline_vertical, 1, sizeof(cl_mem), &coeff);
1532 dt_opencl_set_kernel_arg(devid, gd->kernel_bspline_vertical, 2, sizeof(int), &width);
1533 dt_opencl_set_kernel_arg(devid, gd->kernel_bspline_vertical, 3, sizeof(int), &height);
1534 dt_opencl_set_kernel_arg(devid, gd->kernel_bspline_vertical, 4, sizeof(int), &dense_mult);
1535 dt_opencl_set_kernel_arg(devid, gd->kernel_bspline_vertical, 5, sizeof(int), &keep_signed);
1537 if(err != CL_SUCCESS) goto error;
1538
1539 dt_opencl_set_kernel_arg(devid, gd->kernel_bspline_horizontal, 0, sizeof(cl_mem), &bias);
1540 dt_opencl_set_kernel_arg(devid, gd->kernel_bspline_horizontal, 1, sizeof(cl_mem), &coeff_tmp);
1541 dt_opencl_set_kernel_arg(devid, gd->kernel_bspline_horizontal, 2, sizeof(int), &width);
1542 dt_opencl_set_kernel_arg(devid, gd->kernel_bspline_horizontal, 3, sizeof(int), &height);
1543 dt_opencl_set_kernel_arg(devid, gd->kernel_bspline_horizontal, 4, sizeof(int), &dense_mult);
1544 dt_opencl_set_kernel_arg(devid, gd->kernel_bspline_horizontal, 5, sizeof(int), &keep_signed);
1546 if(err != CL_SUCCESS) goto error;
1547
1548 dt_opencl_set_kernel_arg(devid, gd->kernel_bspline_vertical, 0, sizeof(cl_mem), &coeff_tmp);
1549 dt_opencl_set_kernel_arg(devid, gd->kernel_bspline_vertical, 1, sizeof(cl_mem), &bias);
1550 dt_opencl_set_kernel_arg(devid, gd->kernel_bspline_vertical, 2, sizeof(int), &width);
1551 dt_opencl_set_kernel_arg(devid, gd->kernel_bspline_vertical, 3, sizeof(int), &height);
1552 dt_opencl_set_kernel_arg(devid, gd->kernel_bspline_vertical, 4, sizeof(int), &dense_mult);
1553 dt_opencl_set_kernel_arg(devid, gd->kernel_bspline_vertical, 5, sizeof(int), &keep_signed);
1555 if(err != CL_SUCCESS) goto error;
1556
1557 dt_opencl_set_kernel_arg(devid, gd->kernel_guided_laplacian_apply, 0, sizeof(cl_mem), &temp);
1558 dt_opencl_set_kernel_arg(devid, gd->kernel_guided_laplacian_apply, 1, sizeof(cl_mem), &coeff);
1559 dt_opencl_set_kernel_arg(devid, gd->kernel_guided_laplacian_apply, 2, sizeof(cl_mem), &bias);
1560 dt_opencl_set_kernel_arg(devid, gd->kernel_guided_laplacian_apply, 3, sizeof(cl_mem), &buffer_out);
1561 dt_opencl_set_kernel_arg(devid, gd->kernel_guided_laplacian_apply, 4, sizeof(cl_mem), &reconstructed_read);
1562 dt_opencl_set_kernel_arg(devid, gd->kernel_guided_laplacian_apply, 5, sizeof(cl_mem), &reconstructed_write);
1563 dt_opencl_set_kernel_arg(devid, gd->kernel_guided_laplacian_apply, 6, sizeof(int), &width);
1565 dt_opencl_set_kernel_arg(devid, gd->kernel_guided_laplacian_apply, 8, sizeof(int), &first_scale);
1567 if(err != CL_SUCCESS) goto error;
1568
1569 residual = buffer_out;
1570 reconstructed_final = reconstructed_write;
1571 cl_mem tmp = reconstructed_read;
1572 reconstructed_read = reconstructed_write;
1573 reconstructed_write = tmp;
1574 }
1575
1576 dt_opencl_set_kernel_arg(devid, gd->kernel_guided_laplacian_finalize, 0, sizeof(cl_mem), &reconstructed_final);
1577 dt_opencl_set_kernel_arg(devid, gd->kernel_guided_laplacian_finalize, 1, sizeof(cl_mem), &residual);
1578 dt_opencl_set_kernel_arg(devid, gd->kernel_guided_laplacian_finalize, 2, sizeof(cl_mem), &dev_out);
1582 if(err != CL_SUCCESS) goto error;
1583 }
1584
1585 dt_opencl_release_mem_object(reconstructed_b);
1586 dt_opencl_release_mem_object(reconstructed_a);
1593 return TRUE;
1594
1595error:
1596 dt_opencl_release_mem_object(reconstructed_b);
1597 dt_opencl_release_mem_object(reconstructed_a);
1604 dt_print(DT_DEBUG_OPENCL, "[opencl_demosaic] guided laplacian postfilter failed: %d\n", err);
1605 return FALSE;
1606}
1607
1608int process_cl(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece,
1609 cl_mem dev_in, cl_mem dev_out)
1610{
1611 const dt_iop_roi_t *const roi_in = &piece->roi_in;
1612 const dt_iop_roi_t *const roi_out = &piece->roi_out;
1613 dt_times_t start_time = { 0 }, end_time = { 0 };
1614 const gboolean info = ((darktable.unmuted & (DT_DEBUG_DEMOSAIC | DT_DEBUG_PERF))
1615 && (pipe->type == DT_DEV_PIXELPIPE_FULL));
1616
1619
1620 int demosaicing_method = data->demosaicing_method;
1621
1622 gboolean showmask = FALSE;
1623 if(self->dev->gui_attached && pipe->type == DT_DEV_PIXELPIPE_FULL)
1624 {
1626 if(g) showmask = (g->visual_mask);
1627 // take care of passthru modes
1629 demosaicing_method = (piece->dsc_in.filters != 9u) ? DT_IOP_DEMOSAIC_RCD : DT_IOP_DEMOSAIC_MARKESTEIJN;
1631 demosaicing_method = DT_IOP_DEMOSAIC_PASSTHROUGH_MONOCHROME;
1632 }
1633
1634 cl_mem high_image = NULL;
1635 cl_mem low_image = NULL;
1636 cl_mem blend = NULL;
1637 cl_mem details = NULL;
1638 cl_mem dev_aux = NULL;
1639 cl_mem dev_xtrans = NULL;
1640 const gboolean dual = ((demosaicing_method & DEMOSAIC_DUAL) && (data->dual_thrs > 0.0f));
1641 const int devid = pipe->devid;
1642 gboolean retval = FALSE;
1643
1644 if(info) dt_get_times(&start_time);
1645
1646 if(demosaicing_method == DT_IOP_DEMOSAIC_PASSTHROUGH_MONOCHROME ||
1647 demosaicing_method == DT_IOP_DEMOSAIC_PPG ||
1648 demosaicing_method == DT_IOP_DEMOSAIC_PASSTHROUGH_COLOR )
1649 {
1650 if(!process_default_cl(self, pipe, piece, dev_in, dev_out, roi_in, roi_out, demosaicing_method)) return FALSE;
1651 }
1652 else if(_is_downsample_method(demosaicing_method))
1653 {
1654 const int width = roi_out->width;
1655 const int height = roi_out->height;
1656 size_t sizes[3] = { ROUNDUPDWD(width, devid), ROUNDUPDHT(height, devid), 1 };
1657
1658 if(piece->dsc_in.filters == 9u)
1659 {
1660 dev_xtrans = dt_opencl_copy_host_to_device_constant(devid, sizeof(piece->dsc_in.xtrans),
1661 (void *)piece->dsc_in.xtrans);
1662 if(IS_NULL_PTR(dev_xtrans)) goto finish;
1663
1664 dt_opencl_set_kernel_arg(devid, gd->kernel_zoom_half_size_xtrans, 0, sizeof(cl_mem), &dev_in);
1665 dt_opencl_set_kernel_arg(devid, gd->kernel_zoom_half_size_xtrans, 1, sizeof(cl_mem), &dev_out);
1666 dt_opencl_set_kernel_arg(devid, gd->kernel_zoom_half_size_xtrans, 2, sizeof(int), &width);
1667 dt_opencl_set_kernel_arg(devid, gd->kernel_zoom_half_size_xtrans, 3, sizeof(int), &height);
1668 dt_opencl_set_kernel_arg(devid, gd->kernel_zoom_half_size_xtrans, 4, sizeof(int), (void *)&roi_in->x);
1669 dt_opencl_set_kernel_arg(devid, gd->kernel_zoom_half_size_xtrans, 5, sizeof(int), (void *)&roi_in->y);
1670 dt_opencl_set_kernel_arg(devid, gd->kernel_zoom_half_size_xtrans, 6, sizeof(int), (void *)&roi_in->width);
1671 dt_opencl_set_kernel_arg(devid, gd->kernel_zoom_half_size_xtrans, 7, sizeof(int), (void *)&roi_in->height);
1672 dt_opencl_set_kernel_arg(devid, gd->kernel_zoom_half_size_xtrans, 8, sizeof(cl_mem), (void *)&dev_xtrans);
1673 const cl_int err = dt_opencl_enqueue_kernel_2d(devid, gd->kernel_zoom_half_size_xtrans, sizes);
1674 if(err != CL_SUCCESS) goto finish;
1675 }
1676 else
1677 {
1678 const int zero = 0;
1679 const int is_4bayer = self->dev->image_storage.flags & DT_IMAGE_4BAYER;
1680 const float cam_to_rgb_0[4] = { data->CAM_to_RGB[0][0], data->CAM_to_RGB[0][1],
1681 data->CAM_to_RGB[0][2], data->CAM_to_RGB[0][3] };
1682 const float cam_to_rgb_1[4] = { data->CAM_to_RGB[1][0], data->CAM_to_RGB[1][1],
1683 data->CAM_to_RGB[1][2], data->CAM_to_RGB[1][3] };
1684 const float cam_to_rgb_2[4] = { data->CAM_to_RGB[2][0], data->CAM_to_RGB[2][1],
1685 data->CAM_to_RGB[2][2], data->CAM_to_RGB[2][3] };
1686
1687 dt_opencl_set_kernel_arg(devid, gd->kernel_zoom_half_size, 0, sizeof(cl_mem), &dev_in);
1688 dt_opencl_set_kernel_arg(devid, gd->kernel_zoom_half_size, 1, sizeof(cl_mem), &dev_out);
1689 dt_opencl_set_kernel_arg(devid, gd->kernel_zoom_half_size, 2, sizeof(int), &width);
1690 dt_opencl_set_kernel_arg(devid, gd->kernel_zoom_half_size, 3, sizeof(int), &height);
1691 dt_opencl_set_kernel_arg(devid, gd->kernel_zoom_half_size, 4, sizeof(int), &zero);
1692 dt_opencl_set_kernel_arg(devid, gd->kernel_zoom_half_size, 5, sizeof(int), &zero);
1693 dt_opencl_set_kernel_arg(devid, gd->kernel_zoom_half_size, 6, sizeof(int), (void *)&roi_in->width);
1694 dt_opencl_set_kernel_arg(devid, gd->kernel_zoom_half_size, 7, sizeof(int), (void *)&roi_in->height);
1695 dt_opencl_set_kernel_arg(devid, gd->kernel_zoom_half_size, 8, sizeof(float), (void *)&roi_out->scale);
1696 dt_opencl_set_kernel_arg(devid, gd->kernel_zoom_half_size, 9, sizeof(uint32_t), (void *)&piece->dsc_in.filters);
1697 dt_opencl_set_kernel_arg(devid, gd->kernel_zoom_half_size, 10, sizeof(int), &is_4bayer);
1698 dt_opencl_set_kernel_arg(devid, gd->kernel_zoom_half_size, 11, sizeof(cam_to_rgb_0), cam_to_rgb_0);
1699 dt_opencl_set_kernel_arg(devid, gd->kernel_zoom_half_size, 12, sizeof(cam_to_rgb_1), cam_to_rgb_1);
1700 dt_opencl_set_kernel_arg(devid, gd->kernel_zoom_half_size, 13, sizeof(cam_to_rgb_2), cam_to_rgb_2);
1701 const cl_int err = dt_opencl_enqueue_kernel_2d(devid, gd->kernel_zoom_half_size, sizes);
1702 if(err != CL_SUCCESS) goto finish;
1703 }
1704
1705 if(!_downsample_guided_laplacian_postfilter_cl(self, pipe, dev_out, roi_out, data->color_smoothing)) goto finish;
1706
1707 retval = TRUE;
1708 goto finish;
1709 }
1710 else if((demosaicing_method & ~DEMOSAIC_DUAL) == DT_IOP_DEMOSAIC_RCD)
1711 {
1712 if(dual)
1713 {
1714 high_image = dt_opencl_alloc_device(devid, roi_in->width, roi_in->height, sizeof(float) * 4);
1715 if(IS_NULL_PTR(high_image)) return FALSE;
1716 if(!process_rcd_cl(self, pipe, piece, dev_in, high_image, roi_in, roi_in, FALSE)) goto finish;
1717 }
1718 else
1719 {
1720 if(!process_rcd_cl(self, pipe, piece, dev_in, dev_out, roi_in, roi_out, TRUE)) return FALSE;
1721 }
1722 }
1723 else if(demosaicing_method == DT_IOP_DEMOSAIC_VNG4 || demosaicing_method == DT_IOP_DEMOSAIC_VNG)
1724 {
1725 if(!process_vng_cl(self, pipe, piece, dev_in, dev_out, roi_in, roi_out, TRUE, FALSE)) return FALSE;
1726 }
1727 else if(((demosaicing_method & ~DEMOSAIC_DUAL) == DT_IOP_DEMOSAIC_MARKESTEIJN ) ||
1728 ((demosaicing_method & ~DEMOSAIC_DUAL) == DT_IOP_DEMOSAIC_MARKESTEIJN_3))
1729 {
1730 if(dual)
1731 {
1732 high_image = dt_opencl_alloc_device(devid, roi_in->width, roi_in->height, sizeof(float) * 4);
1733 if(IS_NULL_PTR(high_image)) return FALSE;
1734 if(!process_markesteijn_cl(self, pipe, piece, dev_in, high_image, roi_in, roi_in, FALSE)) return FALSE;
1735 }
1736 else
1737 {
1738 if(!process_markesteijn_cl(self, pipe, piece, dev_in, dev_out, roi_in, roi_out, TRUE)) return FALSE;
1739 }
1740 }
1741 else
1742 {
1743 dt_print(DT_DEBUG_OPENCL, "[opencl_demosaic] demosaicing method '%s' not yet supported by opencl code\n", method2string(demosaicing_method));
1744 return FALSE;
1745 }
1746
1747 if(info)
1748 {
1749 const float mpixels = (roi_in->width * roi_in->height) / 1.0e6;
1750 dt_get_times(&end_time);
1751 const float tclock = end_time.clock - start_time.clock;
1752 const float uclock = end_time.user - start_time.user;
1753 fprintf(stderr," [demosaic] process GPU `%s' did %.2fmpix, %.4f secs (%.4f CPU), %.2f pix/us\n",
1754 method2string(demosaicing_method & ~DEMOSAIC_DUAL), mpixels, tclock, uclock, mpixels / tclock);
1755 }
1756 if(!dual)
1757 {
1758 retval = TRUE;
1759 goto finish;
1760 }
1761
1762 // This is dual demosaicing only stuff
1763 const int scaled = (roi_out->width != roi_in->width || roi_out->height != roi_in->height);
1764
1765 int width = roi_out->width;
1766 int height = roi_out->height;
1767 // need to reserve scaled auxiliary buffer or use dev_out
1768 if(scaled)
1769 {
1770 dev_aux = dt_opencl_alloc_device(devid, roi_in->width, roi_in->height, sizeof(float) * 4);
1771 if(IS_NULL_PTR(dev_aux)) goto finish;
1772 width = roi_in->width;
1773 height = roi_in->height;
1774 }
1775 else
1776 dev_aux = dev_out;
1777
1778 // here we have work to be done only for dual demosaicers
1779 blend = dt_opencl_alloc_device_buffer(devid, sizeof(float) * width * height);
1780 details = dt_opencl_alloc_device_buffer(devid, sizeof(float) * width * height);
1781 low_image = dt_opencl_alloc_device(devid, width, height, sizeof(float) * 4);
1782 if((IS_NULL_PTR(blend)) || (IS_NULL_PTR(low_image)) || (IS_NULL_PTR(details))) goto finish;
1783
1784 if(info) dt_get_times(&start_time);
1785 if(process_vng_cl(self, pipe, piece, dev_in, low_image, roi_in, roi_in, FALSE, FALSE))
1786 {
1787 if(!color_smoothing_cl(self, pipe, piece, low_image, low_image, roi_in, 2))
1788 {
1789 retval = FALSE;
1790 goto finish;
1791 }
1792 retval = dual_demosaic_cl(self, pipe, piece, details, blend, high_image, low_image, dev_aux, width, height, showmask);
1793 }
1794
1795 if(info)
1796 {
1797 dt_get_times(&end_time);
1798 fprintf(stderr," [demosaic] GPU dual blending %.4f secs (%.4f CPU)\n", end_time.clock - start_time.clock, end_time.user - start_time.user);
1799 }
1800
1801 if(scaled)
1802 {
1803 // scale aux buffer to output buffer
1804 const int err = dt_iop_clip_and_zoom_roi_cl(devid, dev_out, dev_aux, roi_out, roi_in);
1805 if(err != CL_SUCCESS)
1806 retval = FALSE;
1807 }
1808
1809 finish:
1810 dt_opencl_release_mem_object(high_image);
1814 if(dev_aux != dev_out) dt_opencl_release_mem_object(dev_aux);
1815 dt_opencl_release_mem_object(dev_xtrans);
1816 if(!retval && dual) dt_control_log(_("[dual demosaic_cl] internal problem"));
1817 return retval;
1818}
1819#endif
1820
1821void tiling_callback(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe, const struct dt_dev_pixelpipe_iop_t *piece, struct dt_develop_tiling_t *tiling)
1822{
1823 const dt_iop_roi_t *const roi_in = &piece->roi_in;
1824 const dt_iop_roi_t *const roi_out = &piece->roi_out;
1826
1827 const float ioratio = (float)roi_out->width * roi_out->height / ((float)roi_in->width * roi_in->height);
1828 const float smooth = data->color_smoothing ? ioratio : 0.0f;
1829 const float greeneq
1830 = ((piece->dsc_in.filters != 9u) && (data->green_eq != DT_IOP_GREEN_EQ_NO)) ? 0.25f : 0.0f;
1831 const dt_iop_demosaic_method_t demosaicing_method = data->demosaicing_method & ~DEMOSAIC_DUAL;
1832
1833 if(demosaicing_method == DT_IOP_DEMOSAIC_DOWNSAMPLE)
1834 {
1835 tiling->factor = 1.0f + ioratio + (data->color_smoothing ? 7.0f * ioratio : 0.0f);
1836 tiling->maxbuf = 1.0f;
1837 tiling->overhead = 0;
1838 tiling->xalign = 1;
1839 tiling->yalign = 1;
1840 tiling->overlap = (piece->dsc_in.filters == 9u) ? 18 : 16;
1841 }
1842 else if((demosaicing_method == DT_IOP_DEMOSAIC_PPG) ||
1843 (demosaicing_method == DT_IOP_DEMOSAIC_PASSTHROUGH_MONOCHROME) ||
1844 (demosaicing_method == DT_IOP_DEMOSAIC_PASSTHROUGH_COLOR) ||
1845 (demosaicing_method == DT_IOP_DEMOSAIC_AMAZE))
1846 {
1847 // Bayer pattern with PPG, Passthrough or Amaze
1848 tiling->factor = 1.0f + ioratio; // in + out
1849 tiling->factor += fmax(1.0f + greeneq, smooth); // + tmp + geeneq | + smooth
1850 tiling->maxbuf = 1.0f;
1851 tiling->overhead = 0;
1852 tiling->xalign = 2;
1853 tiling->yalign = 2;
1854 tiling->overlap = 5; // take care of border handling
1855 }
1856 else if(((demosaicing_method == DT_IOP_DEMOSAIC_MARKESTEIJN) ||
1857 (demosaicing_method == DT_IOP_DEMOSAIC_MARKESTEIJN_3) ||
1858 (demosaicing_method == DT_IOP_DEMOSAIC_FDC)))
1859 {
1860 // X-Trans pattern full Markesteijn processing
1861 const int ndir = (demosaicing_method == DT_IOP_DEMOSAIC_MARKESTEIJN_3) ? 8 : 4;
1862 const int overlap = (demosaicing_method == DT_IOP_DEMOSAIC_MARKESTEIJN_3) ? 18 : 12;
1863
1864 tiling->factor = 1.0f + ioratio;
1865 tiling->factor += ndir * 1.0f // rgb
1866 + ndir * 0.25f // drv
1867 + ndir * 0.125f // homo + homosum
1868 + 1.0f; // aux
1869
1870 tiling->factor += fmax(1.0f + greeneq, smooth);
1871 tiling->maxbuf = 1.0f;
1872 tiling->overhead = 0;
1873 tiling->xalign = XTRANS_SNAPPER;
1874 tiling->yalign = XTRANS_SNAPPER;
1875 tiling->overlap = overlap;
1876 }
1877 else if(demosaicing_method == DT_IOP_DEMOSAIC_RCD)
1878 {
1879 tiling->factor = 1.0f + ioratio;
1880 tiling->factor += fmax(1.0f + greeneq, smooth); // + tmp + geeneq | + smooth
1881 tiling->maxbuf = 1.0f;
1882 tiling->overhead = sizeof(float) * RCD_TILESIZE * RCD_TILESIZE * 8 * MAX(1, darktable.num_openmp_threads);
1883 tiling->xalign = 2;
1884 tiling->yalign = 2;
1885 tiling->overlap = 10;
1886 tiling->factor_cl = tiling->factor + 3.0f;
1887 }
1888 else if(demosaicing_method == DT_IOP_DEMOSAIC_LMMSE)
1889 {
1890 tiling->factor = 1.0f + ioratio;
1891 tiling->factor += fmax(1.0f + greeneq, smooth); // + tmp + geeneq | + smooth
1892 tiling->maxbuf = 1.0f;
1893 tiling->overhead = sizeof(float) * LMMSE_GRP * LMMSE_GRP * 6 * MAX(1, darktable.num_openmp_threads);
1894 tiling->xalign = 2;
1895 tiling->yalign = 2;
1896 tiling->overlap = 10;
1897 }
1898 else
1899 {
1900 // VNG
1901 tiling->factor = 1.0f + ioratio;
1902 tiling->factor += fmax(1.0f + greeneq, smooth);
1903 tiling->maxbuf = 1.0f;
1904 tiling->overhead = 0;
1905 tiling->xalign = 6; // covering Bayer pattern for VNG4 as well as xtrans for VNG
1906 tiling->yalign = 6; // covering Bayer pattern for VNG4 as well as xtrans for VNG
1907 tiling->overlap = 6;
1908 }
1910 {
1911 // make sure VNG4 is also possible
1912 tiling->factor += 1.0f;
1913 tiling->xalign = MAX(6, tiling->xalign);
1914 tiling->yalign = MAX(6, tiling->yalign);
1915 tiling->overlap = MAX(6, tiling->overlap);
1916 }
1917 return;
1918}
1919#undef LMMSE_GRP
1920
1922{
1923 const int program = 0; // from programs.conf
1926 module->data = gd;
1927 gd->kernel_zoom_half_size = dt_opencl_create_kernel(program, "clip_and_zoom_demosaic_half_size");
1928 gd->kernel_ppg_green = dt_opencl_create_kernel(program, "ppg_demosaic_green");
1929 gd->kernel_green_eq_lavg = dt_opencl_create_kernel(program, "green_equilibration_lavg");
1930 gd->kernel_green_eq_favg_reduce_first = dt_opencl_create_kernel(program, "green_equilibration_favg_reduce_first");
1931 gd->kernel_green_eq_favg_reduce_second = dt_opencl_create_kernel(program, "green_equilibration_favg_reduce_second");
1932 gd->kernel_green_eq_favg_apply = dt_opencl_create_kernel(program, "green_equilibration_favg_apply");
1933 gd->kernel_pre_median = dt_opencl_create_kernel(program, "pre_median");
1934 gd->kernel_ppg_redblue = dt_opencl_create_kernel(program, "ppg_demosaic_redblue");
1935 gd->kernel_downsample = dt_opencl_create_kernel(program, "clip_and_zoom");
1936 gd->kernel_border_interpolate = dt_opencl_create_kernel(program, "border_interpolate");
1937 gd->kernel_color_smoothing = dt_opencl_create_kernel(program, "color_smoothing");
1938
1939 const int other = 14; // from programs.conf
1940 gd->kernel_passthrough_monochrome = dt_opencl_create_kernel(other, "passthrough_monochrome");
1941 gd->kernel_passthrough_color = dt_opencl_create_kernel(other, "passthrough_color");
1942 gd->kernel_zoom_passthrough_monochrome = dt_opencl_create_kernel(other, "clip_and_zoom_demosaic_passthrough_monochrome");
1943
1944 const int vng = 15; // from programs.conf
1945 gd->kernel_vng_border_interpolate = dt_opencl_create_kernel(vng, "vng_border_interpolate");
1946 gd->kernel_vng_lin_interpolate = dt_opencl_create_kernel(vng, "vng_lin_interpolate");
1947 gd->kernel_zoom_third_size = dt_opencl_create_kernel(vng, "clip_and_zoom_demosaic_third_size_xtrans");
1948 gd->kernel_zoom_half_size_xtrans = dt_opencl_create_kernel(vng, "clip_and_zoom_demosaic_half_size_xtrans");
1949 gd->kernel_vng_green_equilibrate = dt_opencl_create_kernel(vng, "vng_green_equilibrate");
1950 gd->kernel_vng_interpolate = dt_opencl_create_kernel(vng, "vng_interpolate");
1951
1952 const int markesteijn = 16; // from programs.conf
1953 gd->kernel_markesteijn_initial_copy = dt_opencl_create_kernel(markesteijn, "markesteijn_initial_copy");
1954 gd->kernel_markesteijn_green_minmax = dt_opencl_create_kernel(markesteijn, "markesteijn_green_minmax");
1955 gd->kernel_markesteijn_interpolate_green = dt_opencl_create_kernel(markesteijn, "markesteijn_interpolate_green");
1956 gd->kernel_markesteijn_solitary_green = dt_opencl_create_kernel(markesteijn, "markesteijn_solitary_green");
1957 gd->kernel_markesteijn_recalculate_green = dt_opencl_create_kernel(markesteijn, "markesteijn_recalculate_green");
1958 gd->kernel_markesteijn_red_and_blue = dt_opencl_create_kernel(markesteijn, "markesteijn_red_and_blue");
1959 gd->kernel_markesteijn_interpolate_twoxtwo = dt_opencl_create_kernel(markesteijn, "markesteijn_interpolate_twoxtwo");
1960 gd->kernel_markesteijn_convert_yuv = dt_opencl_create_kernel(markesteijn, "markesteijn_convert_yuv");
1961 gd->kernel_markesteijn_differentiate = dt_opencl_create_kernel(markesteijn, "markesteijn_differentiate");
1962 gd->kernel_markesteijn_homo_threshold = dt_opencl_create_kernel(markesteijn, "markesteijn_homo_threshold");
1963 gd->kernel_markesteijn_homo_set = dt_opencl_create_kernel(markesteijn, "markesteijn_homo_set");
1964 gd->kernel_markesteijn_homo_sum = dt_opencl_create_kernel(markesteijn, "markesteijn_homo_sum");
1965 gd->kernel_markesteijn_homo_max = dt_opencl_create_kernel(markesteijn, "markesteijn_homo_max");
1966 gd->kernel_markesteijn_homo_max_corr = dt_opencl_create_kernel(markesteijn, "markesteijn_homo_max_corr");
1967 gd->kernel_markesteijn_homo_quench = dt_opencl_create_kernel(markesteijn, "markesteijn_homo_quench");
1968 gd->kernel_markesteijn_zero = dt_opencl_create_kernel(markesteijn, "markesteijn_zero");
1969 gd->kernel_markesteijn_accu = dt_opencl_create_kernel(markesteijn, "markesteijn_accu");
1970 gd->kernel_markesteijn_final = dt_opencl_create_kernel(markesteijn, "markesteijn_final");
1971
1972 const int rcd = 31; // from programs.conf
1973 gd->kernel_rcd_populate = dt_opencl_create_kernel(rcd, "rcd_populate");
1974 gd->kernel_rcd_write_output = dt_opencl_create_kernel(rcd, "rcd_write_output");
1975 gd->kernel_rcd_step_1 = dt_opencl_create_kernel(rcd, "rcd_step_1");
1976 gd->kernel_rcd_step_2_1 = dt_opencl_create_kernel(rcd, "rcd_step_2_1");
1977 gd->kernel_rcd_step_3_1 = dt_opencl_create_kernel(rcd, "rcd_step_3_1");
1978 gd->kernel_rcd_step_4_1 = dt_opencl_create_kernel(rcd, "rcd_step_4_1");
1979 gd->kernel_rcd_step_4_2 = dt_opencl_create_kernel(rcd, "rcd_step_4_2");
1980 gd->kernel_rcd_step_5_1 = dt_opencl_create_kernel(rcd, "rcd_step_5_1");
1981 gd->kernel_rcd_step_5_2 = dt_opencl_create_kernel(rcd, "rcd_step_5_2");
1982 gd->kernel_rcd_border_redblue = dt_opencl_create_kernel(rcd, "rcd_border_redblue");
1983 gd->kernel_rcd_border_green = dt_opencl_create_kernel(rcd, "rcd_border_green");
1984 gd->kernel_write_blended_dual = dt_opencl_create_kernel(rcd, "write_blended_dual");
1985
1986 const int wavelets = 35; // bspline.cl, from programs.conf
1987 gd->kernel_guided_laplacian_coefficients = dt_opencl_create_kernel(wavelets, "guided_laplacian_coefficients");
1988 gd->kernel_guided_laplacian_normalize = dt_opencl_create_kernel(wavelets, "guided_laplacian_normalize");
1989 gd->kernel_guided_laplacian_apply = dt_opencl_create_kernel(wavelets, "guided_laplacian_apply");
1990 gd->kernel_guided_laplacian_finalize = dt_opencl_create_kernel(wavelets, "guided_laplacian_finalize");
1991 gd->kernel_bspline_horizontal = dt_opencl_create_kernel(wavelets, "blur_2D_Bspline_horizontal");
1992 gd->kernel_bspline_vertical = dt_opencl_create_kernel(wavelets, "blur_2D_Bspline_vertical");
1993 gd->kernel_bspline_horizontal_local = dt_opencl_create_kernel(wavelets, "blur_2D_Bspline_horizontal_local");
1994 gd->kernel_bspline_vertical_local = dt_opencl_create_kernel(wavelets, "blur_2D_Bspline_vertical_local");
1995 gd->lmmse_gamma_in = NULL;
1996 gd->lmmse_gamma_out = NULL;
1997}
1998
2000{
2062 dt_free(module->data);
2063}
2064
2065
2066gboolean force_enable(struct dt_iop_module_t *self, const gboolean current_state)
2067{
2068 // Demosaicing applies if and only if the buffer carries a CFA mosaic. Gate on the mosaic
2069 // axis, not on the historical "raw" flag: an already-demosaiced raw (sRAW / linear DNG) must
2070 // not be demosaiced, while a mosaiced raw that the RAW flag missed still must.
2071 // Mandatory module: the decision is purely image metadata and ignores current_state.
2072 const gboolean state = dt_image_needs_demosaic(&self->dev->image_storage);
2073 dt_iop_fmt_log(self, "force_enable: class=%s needs_demosaic=%d current=%d -> %d",
2075 state, current_state, state);
2076 return state;
2077}
2078
2079
2082{
2085
2086 d->green_eq = p->green_eq;
2087 d->color_smoothing = p->color_smoothing;
2088 d->median_thrs = p->median_thrs;
2089 d->dual_thrs = p->dual_thrs;
2090 d->lmmse_refine = p->lmmse_refine;
2091 dt_iop_demosaic_method_t use_method = p->demosaicing_method;
2092 const gboolean xmethod = use_method & DEMOSAIC_XTRANS;
2093 const gboolean bayer = (self->dev->image_storage.dsc.filters != 9u);
2094 const gboolean downsample = _is_downsample_method(use_method);
2095
2096 if(!downsample)
2097 {
2098 if(bayer && xmethod) use_method = DT_IOP_DEMOSAIC_RCD;
2099 if(!bayer && !xmethod) use_method = DT_IOP_DEMOSAIC_MARKESTEIJN;
2100 }
2101
2104 if(use_method == DT_IOP_DEMOSAIC_PASSTHROUGH_COLOR || use_method == DT_IOP_DEMOSAIC_PASSTHR_COLORX)
2106
2107 const gboolean passing = (use_method == DT_IOP_DEMOSAIC_PASSTHROUGH_MONOCHROME
2108 || use_method == DT_IOP_DEMOSAIC_PASSTHROUGH_COLOR);
2109
2110 if(!(use_method == DT_IOP_DEMOSAIC_PPG))
2111 d->median_thrs = 0.0f;
2112
2113 if(passing)
2114 {
2115 d->green_eq = DT_IOP_GREEN_EQ_NO;
2116 d->color_smoothing = 0;
2117 d->dual_thrs = 0.0f;
2118 }
2119 else if(downsample)
2120 {
2121 d->green_eq = DT_IOP_GREEN_EQ_NO;
2122 d->dual_thrs = 0.0f;
2123 }
2124
2125 if(use_method & DEMOSAIC_DUAL)
2126 d->color_smoothing = 0;
2127
2128 d->demosaicing_method = use_method;
2129
2130 // OpenCL only supported by some of the demosaicing methods
2131 switch(d->demosaicing_method)
2132 {
2134 piece->process_cl_ready = 1;
2135 break;
2137 piece->process_cl_ready = 0;
2138 break;
2140 piece->process_cl_ready = 1;
2141 break;
2143 piece->process_cl_ready = 1;
2144 break;
2146 piece->process_cl_ready = 1;
2147 break;
2149 piece->process_cl_ready = 1;
2150 break;
2152 piece->process_cl_ready = 0;
2153 break;
2155 piece->process_cl_ready = 1;
2156 break;
2158 piece->process_cl_ready = 0;
2159 break;
2161 piece->process_cl_ready = 1;
2162 break;
2164 piece->process_cl_ready = 1;
2165 break;
2167 piece->process_cl_ready = 1;
2168 break;
2170 piece->process_cl_ready = 1;
2171 break;
2173 piece->process_cl_ready = 0;
2174 break;
2176 piece->process_cl_ready = 1;
2177 break;
2178 default:
2179 piece->process_cl_ready = 0;
2180 }
2181
2182 // green-equilibrate over full image excludes tiling
2183 if((d->green_eq == DT_IOP_GREEN_EQ_FULL
2184 || d->green_eq == DT_IOP_GREEN_EQ_BOTH)
2185 || ((use_method & DEMOSAIC_DUAL) && (d->dual_thrs > 0.0f)))
2186 {
2187 piece->process_tiling_ready = 0;
2188 }
2189
2191 {
2192 // 4Bayer images only support the dedicated half-size downsample path in OpenCL.
2193 if(d->demosaicing_method != DT_IOP_DEMOSAIC_DOWNSAMPLE) piece->process_cl_ready = 0;
2194
2195 // Get and store the matrix to go from camera to RGB for 4Bayer images
2197 NULL, d->CAM_to_RGB,
2198 self->dev->image_storage.d65_color_matrix, NULL))
2199 {
2200 const char *camera = self->dev->image_storage.camera_makermodel;
2201 fprintf(stderr, "[colorspaces] `%s' color matrix not found for 4bayer image!\n", camera);
2202 dt_control_log(_("`%s' color matrix not found for 4bayer image!"), camera);
2203 }
2204 }
2205
2206 dt_iop_fmt_log(self, "commit: class=%s in(filters=%u ch=%i) method=%d passthrough=%d -> enabled=%d cl_ready=%d",
2208 piece->dsc_in.filters, piece->dsc_in.channels, d->demosaicing_method, passing,
2209 piece->enabled, piece->process_cl_ready);
2210}
2211
2213{
2215 piece->data_size = sizeof(dt_iop_demosaic_data_t);
2216}
2217
2219{
2220 dt_free_align(piece->data);
2221 piece->data = NULL;
2222}
2223
2225{
2227
2229 d->demosaicing_method = DT_IOP_DEMOSAIC_PASSTHROUGH_MONOCHROME;
2230 else if(module->dev->image_storage.dsc.filters == 9u)
2231 d->demosaicing_method = DT_IOP_DEMOSAIC_MARKESTEIJN;
2232 else
2233 d->demosaicing_method = DT_IOP_DEMOSAIC_RCD;
2234
2235 module->hide_enable_button = 1;
2236
2237 // Enabled iff the buffer is mosaiced (see force_enable): keeps demosaic off for
2238 // already-demosaiced sRAW / linear DNG and on for monochrome Bayer sensors.
2239 module->default_enabled = dt_image_needs_demosaic(&module->dev->image_storage);
2240 dt_iop_fmt_log(module, "reload_defaults: class=%s needs_demosaic=%d filters=%u mono=%d method=%d -> default_enabled=%d",
2243 module->dev->image_storage.dsc.filters,
2245 d->demosaicing_method, module->default_enabled);
2246 if(module->widget)
2247 gtk_stack_set_visible_child_name(GTK_STACK(module->widget), module->default_enabled ? "raw" : "non_raw");
2248}
2249
2250void gui_changed(dt_iop_module_t *self, GtkWidget *w, void *previous)
2251{
2254
2255 const gboolean bayer = (self->dev->image_storage.dsc.filters != 9u);
2256 dt_iop_demosaic_method_t use_method = p->demosaicing_method;
2257 const gboolean xmethod = use_method & DEMOSAIC_XTRANS;
2258
2259 if(!_is_downsample_method(use_method))
2260 {
2261 if(bayer && xmethod) use_method = DT_IOP_DEMOSAIC_RCD;
2262 if(!bayer && !xmethod) use_method = DT_IOP_DEMOSAIC_MARKESTEIJN;
2263 }
2264
2265 const gboolean isppg = (use_method == DT_IOP_DEMOSAIC_PPG);
2266 const gboolean isdownsample = _is_downsample_method(use_method);
2267 const gboolean isdual = !isdownsample && (use_method & DEMOSAIC_DUAL);
2268 const gboolean islmmse = (use_method == DT_IOP_DEMOSAIC_LMMSE);
2269 const gboolean passing = ((use_method == DT_IOP_DEMOSAIC_PASSTHROUGH_MONOCHROME) ||
2270 (use_method == DT_IOP_DEMOSAIC_PASSTHROUGH_COLOR) ||
2271 (use_method == DT_IOP_DEMOSAIC_PASSTHR_MONOX) ||
2272 (use_method == DT_IOP_DEMOSAIC_PASSTHR_COLORX));
2273
2274 gtk_widget_set_visible(g->demosaic_method_bayer, bayer);
2275 gtk_widget_set_visible(g->demosaic_method_xtrans, !bayer);
2276 if(bayer)
2277 dt_bauhaus_combobox_set_from_value(g->demosaic_method_bayer, p->demosaicing_method);
2278 else
2279 dt_bauhaus_combobox_set_from_value(g->demosaic_method_xtrans, p->demosaicing_method);
2280
2281 gtk_widget_set_visible(g->median_thrs, bayer && isppg);
2282 gtk_widget_set_visible(g->greeneq, !passing && !isdownsample);
2283 gtk_widget_set_visible(g->color_smoothing, !passing && !isdual);
2284 gtk_widget_set_visible(g->dual_thrs, isdual);
2285 gtk_widget_set_visible(g->lmmse_refine, islmmse);
2286
2288 if((p->demosaicing_method == DT_IOP_DEMOSAIC_PASSTHROUGH_MONOCHROME) ||
2289 (p->demosaicing_method == DT_IOP_DEMOSAIC_PASSTHR_MONOX))
2291 else
2292 img->flags &= ~DT_IMAGE_MONOCHROME_BAYER;
2294}
2295void gui_update(struct dt_iop_module_t *self)
2296{
2299
2300 g->visual_mask = FALSE;
2301 gui_changed(self, NULL, NULL);
2302
2303 gtk_stack_set_visible_child_name(GTK_STACK(self->widget), self->default_enabled ? "raw" : "non_raw");
2304}
2305
2306static void _visualize_callback(GtkWidget *quad, gpointer user_data)
2307{
2308 if(darktable.gui->reset) return;
2309 dt_iop_module_t *self = (dt_iop_module_t *)user_data;
2311
2312 g->visual_mask = dt_bauhaus_widget_get_quad_active(quad);
2314}
2315
2316void gui_focus(struct dt_iop_module_t *self, gboolean in)
2317{
2319 if(!in)
2320 {
2321 const gboolean was_dualmask = g->visual_mask;
2323 g->visual_mask = FALSE;
2324 if(was_dualmask) dt_dev_pixelpipe_update_history_main(self->dev);
2325 }
2326}
2327
2328void gui_init(struct dt_iop_module_t *self)
2329{
2331
2332 GtkWidget *box_raw = self->widget = gtk_box_new(GTK_ORIENTATION_VERTICAL, DT_GUI_BOX_SPACING);
2333
2334 g->demosaic_method_bayer = dt_bauhaus_combobox_from_params(self, "demosaicing_method");
2335 for(int i=0;i<7;i++) dt_bauhaus_combobox_remove_at(g->demosaic_method_bayer, 9);
2336 gtk_widget_set_tooltip_text(g->demosaic_method_bayer, _("Bayer sensor demosaicing method, PPG and RCD are fast, AMaZE and LMMSE are slow.\nLMMSE is suited best for high ISO images.\ndual demosaicers double processing time."));
2337
2338 g->demosaic_method_xtrans = dt_bauhaus_combobox_from_params(self, "demosaicing_method");
2339 for(int i=0;i<9;i++) dt_bauhaus_combobox_remove_at(g->demosaic_method_xtrans, 0);
2340 gtk_widget_set_tooltip_text(g->demosaic_method_xtrans, _("X-Trans sensor demosaicing method, Markesteijn 3-pass and frequency domain chroma are slow.\ndual demosaicers double processing time."));
2341
2342 g->median_thrs = dt_bauhaus_slider_from_params(self, "median_thrs");
2343 dt_bauhaus_slider_set_digits(g->median_thrs, 3);
2344 gtk_widget_set_tooltip_text(g->median_thrs, _("threshold for edge-aware median.\nset to 0.0 to switch off\n"
2345 "set to 1.0 to ignore edges"));
2346
2347 g->dual_thrs = dt_bauhaus_slider_from_params(self, "dual_thrs");
2348 dt_bauhaus_slider_set_digits(g->dual_thrs, 2);
2349 gtk_widget_set_tooltip_text(g->dual_thrs, _("contrast threshold for dual demosaic.\nset to 0.0 for high frequency content\n"
2350 "set to 1.0 for flat content\ntoggle to visualize the mask"));
2354 g_signal_connect(G_OBJECT(g->dual_thrs), "quad-pressed", G_CALLBACK(_visualize_callback), self);
2355
2356 g->lmmse_refine = dt_bauhaus_combobox_from_params(self, "lmmse_refine");
2357 gtk_widget_set_tooltip_text(g->lmmse_refine, _("LMMSE refinement steps. the median steps average the output,\nrefine adds some recalculation of red & blue channels"));
2358
2359 g->color_smoothing = dt_bauhaus_combobox_from_params(self, "color_smoothing");
2360 gtk_widget_set_tooltip_text(g->color_smoothing, _("how many post-demosaic smoothing passes.\nin downsample mode this sets the guided detail equalization iterations"));
2361
2362 g->greeneq = dt_bauhaus_combobox_from_params(self, "green_eq");
2363 gtk_widget_set_tooltip_text(g->greeneq, _("green channels matching method"));
2364
2365 // start building top level widget
2366 self->widget = gtk_stack_new();
2367 gtk_stack_set_homogeneous(GTK_STACK(self->widget), FALSE);
2368
2369 GtkWidget *label_non_raw = dt_ui_label_new(_("not applicable"));
2370 gtk_widget_set_tooltip_text(label_non_raw, _("demosaicing is only used for color raw images"));
2371
2372 gtk_stack_add_named(GTK_STACK(self->widget), label_non_raw, "non_raw");
2373 gtk_stack_add_named(GTK_STACK(self->widget), box_raw, "raw");
2374}
2375
2376// clang-format off
2377// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
2378// vim: shiftwidth=2 expandtab tabstop=2 cindent
2379// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
2380// clang-format on
static void error(char *msg)
Definition ashift_lsd.c:202
#define TRUE
Definition ashift_lsd.c:162
#define FALSE
Definition ashift_lsd.c:158
void cleanup(dt_imageio_module_format_t *self)
Definition avif.c:164
static __DT_CLONE_TARGETS__ void green_equilibration_lavg(float *out, const float *const in, const int width, const int height, const uint32_t filters, const int x, const int y, const float thr)
Definition basic.c:248
static int green_equilibration_cl(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, cl_mem dev_in, cl_mem dev_out, const dt_iop_roi_t *const roi_in)
Definition basic.c:400
static __DT_CLONE_TARGETS__ void green_equilibration_favg(float *out, const float *const in, const int width, const int height, const uint32_t filters, const int x, const int y)
Definition basic.c:296
static __DT_CLONE_TARGETS__ void color_smoothing(float *out, const dt_iop_roi_t *const roi_out, const int num_passes)
Definition basic.c:192
static int color_smoothing_cl(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, cl_mem dev_in, cl_mem dev_out, const dt_iop_roi_t *const roi_out, const int passes)
Definition basic.c:334
void dt_bauhaus_slider_set_digits(GtkWidget *widget, int val)
Definition bauhaus.c:3534
gboolean dt_bauhaus_combobox_set_from_value(GtkWidget *widget, int value)
Definition bauhaus.c:2330
void dt_bauhaus_widget_set_quad_toggle(GtkWidget *widget, int toggle)
Definition bauhaus.c:1720
void dt_bauhaus_widget_set_quad_active(GtkWidget *widget, int active)
Definition bauhaus.c:1726
int dt_bauhaus_widget_get_quad_active(GtkWidget *widget)
Definition bauhaus.c:1743
void dt_bauhaus_combobox_remove_at(GtkWidget *widget, int pos)
Definition bauhaus.c:2101
void dt_bauhaus_widget_set_quad_paint(GtkWidget *widget, dt_bauhaus_quad_paint_f f, int paint_flags, void *paint_data)
Definition bauhaus.c:1702
int width
Definition bilateral.h:1
int height
Definition bilateral.h:1
static void blur_2D_Bspline(const float *const restrict in, float *const restrict out, float *const restrict tempbuf, const size_t width, const size_t height, const int mult, const gboolean clip_negatives)
Definition bspline.h:325
#define BSPLINE_FSIZE
Definition bspline.h:30
static void decompose_2D_Bspline(const float *const restrict in, float *const restrict HF, float *const restrict LF, const size_t width, const size_t height, const int mult, float *const tempbuf, size_t padded_size)
Definition bspline.h:347
static float intp(const float a, const float b, const float c)
Definition cacorrect.c:180
static const dt_aligned_pixel_simd_t const dt_adaptation_t const float p
return vector dt_simd_set1(valid ?(scaling+NORM_MIN) :NORM_MIN)
@ IOP_CS_RAW
@ IOP_CS_RGB
__DT_CLONE_TARGETS__ int dt_colorspaces_conversion_matrices_rgb(const float adobe_XYZ_to_CAM[4][3], double out_RGB_to_CAM[4][3], double out_CAM_to_RGB[3][4], const float *embedded_matrix, double mul[4])
__DT_CLONE_TARGETS__ void dt_colorspaces_cygm_to_rgb(float *out, int num, double CAM_to_RGB[3][4])
static dt_aligned_pixel_t rgb
const float threshold
const dt_colormatrix_t dt_aligned_pixel_t out
dt_store_simd_aligned(out, dt_mat3x4_mul_vec4(vin, dt_colormatrix_row_to_simd(matrix, 0), dt_colormatrix_row_to_simd(matrix, 1), dt_colormatrix_row_to_simd(matrix, 2)))
const float top
static const int row
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
dt_image_pipe_class_t dt_image_pipe_class(const dt_image_t *img)
const char * dt_image_pipe_class_name(const dt_image_pipe_class_t klass)
gboolean dt_image_is_monochrome(const dt_image_t *img)
gboolean dt_image_needs_demosaic(const dt_image_t *img)
void dt_control_log(const char *msg,...)
Definition control.c:761
void reset(dt_view_t *self)
Definition darkroom.c:1266
darktable_t darktable
Definition darktable.c:181
void dt_print(dt_debug_thread_t thread, const char *msg,...)
Definition darktable.c:1542
static const dt_aligned_pixel_simd_t const dt_aligned_pixel_simd_t row1
Definition darktable.h:623
#define dt_free_align(ptr)
Definition darktable.h:481
static void * dt_calloc_align(size_t size)
Definition darktable.h:488
@ DT_DEBUG_OPENCL
Definition darktable.h:722
@ DT_DEBUG_DEMOSAIC
Definition darktable.h:737
@ DT_DEBUG_PERF
Definition darktable.h:719
#define dt_pixelpipe_cache_alloc_align_float_cache(pixels, id)
Definition darktable.h:447
float dt_aligned_pixel_simd_t __attribute__((vector_size(16), aligned(16)))
Enable aggressive floating-point arithmetic optimizations, in denormals handling. Set through user pr...
Definition darktable.h:524
#define dt_free(ptr)
Definition darktable.h:456
static void dt_get_times(dt_times_t *t)
Definition darktable.h:921
#define DT_MODULE_INTROSPECTION(MODVER, PARAMSTYPE)
Definition darktable.h:151
#define dt_pixelpipe_cache_free_align(mem)
Definition darktable.h:453
#define dt_pixelpipe_cache_alloc_align_float(pixels, pipe)
Definition darktable.h:442
#define __DT_CLONE_TARGETS__
Definition darktable.h:367
static const dt_aligned_pixel_simd_t const dt_aligned_pixel_simd_t const dt_aligned_pixel_simd_t row2
Definition darktable.h:624
#define __OMP_PARALLEL_FOR__(...)
Definition darktable.h:258
#define dt_pixelpipe_cache_alloc_perthread_float(n, padded_size)
Definition darktable.h:1030
static const dt_aligned_pixel_simd_t row0
Definition darktable.h:622
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
Definition darktable.h:281
#define BLUE
#define RED
#define GREEN
static int FCxtrans(const int row, const int col, global const unsigned char(*const xtrans)[6])
static int FC(const int row, const int col, const unsigned int filters)
#define ALPHA
dt_iop_demosaic_method_t
Definition demosaic.c:111
@ DT_IOP_DEMOSAIC_MARKESTEIJN_3
Definition demosaic.c:125
@ DT_IOP_DEMOSAIC_RCD
Definition demosaic.c:116
@ DT_IOP_DEMOSAIC_RCD_VNG
Definition demosaic.c:118
@ DT_IOP_DEMOSAIC_MARKESTEIJN
Definition demosaic.c:124
@ DT_IOP_DEMOSAIC_PASSTHROUGH_COLOR
Definition demosaic.c:121
@ DT_IOP_DEMOSAIC_PASSTHR_MONOX
Definition demosaic.c:128
@ DT_IOP_DEMOSAIC_VNG4
Definition demosaic.c:115
@ DT_IOP_DEMOSAIC_PPG
Definition demosaic.c:113
@ DT_IOP_DEMOSAIC_MARKEST3_VNG
Definition demosaic.c:127
@ DT_IOP_DEMOSAIC_LMMSE
Definition demosaic.c:117
@ DT_IOP_DEMOSAIC_VNG
Definition demosaic.c:123
@ DT_IOP_DEMOSAIC_AMAZE_VNG
Definition demosaic.c:119
@ DT_IOP_DEMOSAIC_DOWNSAMPLE
Definition demosaic.c:130
@ DT_IOP_DEMOSAIC_PASSTHR_COLORX
Definition demosaic.c:129
@ DT_IOP_DEMOSAIC_FDC
Definition demosaic.c:126
@ DT_IOP_DEMOSAIC_PASSTHROUGH_MONOCHROME
Definition demosaic.c:120
@ DT_IOP_DEMOSAIC_AMAZE
Definition demosaic.c:114
void distort_mask(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe, struct dt_dev_pixelpipe_iop_t *piece, const float *const in, float *const out, const dt_iop_roi_t *const roi_in, const dt_iop_roi_t *const roi_out)
Definition demosaic.c:905
static int process_default_cl(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, cl_mem dev_in, cl_mem dev_out, const dt_iop_roi_t *const roi_in, const dt_iop_roi_t *const roi_out, const int demosaicing_method)
Definition demosaic.c:1177
const char ** description(struct dt_iop_module_t *self)
Definition demosaic.c:305
int default_group()
Definition demosaic.c:314
void modify_roi_out(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe, struct dt_dev_pixelpipe_iop_t *piece, dt_iop_roi_t *roi_out, const dt_iop_roi_t *const roi_in)
Definition demosaic.c:914
static gboolean _downsample_guided_laplacian_postfilter_cl(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, cl_mem dev_out, const dt_iop_roi_t *const roi_out, const int iterations)
Definition demosaic.c:1358
static __DT_CLONE_TARGETS__ void _downsample_bayer_half_size(float *const out, const float *const in, const dt_iop_roi_t *const roi_out, const dt_iop_roi_t *const roi_in, const uint32_t filters, const gboolean is_4bayer, const double CAM_to_RGB[3][4])
Build one half-size RGB pixel from the 2x2 CFA block backing it.
Definition demosaic.c:458
void reload_defaults(dt_iop_module_t *module)
Definition demosaic.c:2224
void amaze_demosaic_RT(const dt_dev_pixelpipe_iop_t *piece, const float *const in, float *out, const dt_iop_roi_t *const roi_in, const dt_iop_roi_t *const roi_out, const uint32_t filters)
void commit_params(struct dt_iop_module_t *self, dt_iop_params_t *params, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Definition demosaic.c:2080
dt_iop_demosaic_smooth_t
Definition demosaic.c:143
@ DEMOSAIC_SMOOTH_2
Definition demosaic.c:146
@ DEMOSAIC_SMOOTH_3
Definition demosaic.c:147
@ DEMOSAIC_SMOOTH_1
Definition demosaic.c:145
@ DEMOSAIC_SMOOTH_OFF
Definition demosaic.c:144
@ DEMOSAIC_SMOOTH_4
Definition demosaic.c:148
@ DEMOSAIC_SMOOTH_5
Definition demosaic.c:149
static __DT_CLONE_TARGETS__ void _downsample_xtrans_half_size(float *const out, const float *const in, const dt_iop_roi_t *const roi_out, const dt_iop_roi_t *const roi_in, const uint8_t(*const xtrans)[6])
Build one half-size RGB pixel from a 2x2 X-Trans block.
Definition demosaic.c:602
dt_iop_demosaic_lmmse_t
Definition demosaic.c:153
@ LMMSE_REFINE_0
Definition demosaic.c:154
@ LMMSE_REFINE_3
Definition demosaic.c:157
@ LMMSE_REFINE_4
Definition demosaic.c:158
@ LMMSE_REFINE_2
Definition demosaic.c:156
@ LMMSE_REFINE_1
Definition demosaic.c:155
#define DEMOSAIC_DUAL
Definition demosaic.c:101
void gui_focus(struct dt_iop_module_t *self, gboolean in)
Definition demosaic.c:2316
void init_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Definition demosaic.c:2212
static __DT_CLONE_TARGETS__ int _downsample_guided_laplacian_postfilter(float *const out, const size_t width, const size_t height, const int iterations)
Denoise the half-size demosaic result by filtering its wavelet details.
Definition demosaic.c:787
dt_iop_demosaic_greeneq_t
Definition demosaic.c:134
@ DT_IOP_GREEN_EQ_LOCAL
Definition demosaic.c:136
@ DT_IOP_GREEN_EQ_FULL
Definition demosaic.c:137
@ DT_IOP_GREEN_EQ_BOTH
Definition demosaic.c:138
@ DT_IOP_GREEN_EQ_NO
Definition demosaic.c:135
const char * name()
Definition demosaic.c:300
void output_format(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece, dt_iop_buffer_dsc_t *dsc)
Definition demosaic.c:373
void gui_update(struct dt_iop_module_t *self)
Definition demosaic.c:2295
#define DEMOSAIC_XTRANS
Definition demosaic.c:100
void gui_init(struct dt_iop_module_t *self)
Definition demosaic.c:2328
static gboolean _is_downsample_method(const dt_iop_demosaic_method_t method)
Definition demosaic.c:444
void gui_changed(dt_iop_module_t *self, GtkWidget *w, void *previous)
Definition demosaic.c:2250
dt_iop_demosaic_quality_t
Definition demosaic.c:249
@ DT_DEMOSAIC_BEST
Definition demosaic.c:252
@ DT_DEMOSAIC_FAIR
Definition demosaic.c:251
@ DT_DEMOSAIC_FAST
Definition demosaic.c:250
void tiling_callback(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe, const struct dt_dev_pixelpipe_iop_t *piece, struct dt_develop_tiling_t *tiling)
Definition demosaic.c:1821
static __DT_CLONE_TARGETS__ void _downsample_guided_laplacian_apply(const float *const restrict HF, const float *const restrict coeff, const float *const restrict bias, const float *const restrict LF, float *const restrict reconstructed, const size_t width, const size_t height, const gboolean reset)
Apply the locally averaged affine RGB model to one high-frequency layer.
Definition demosaic.c:747
void cleanup_global(dt_iop_module_so_t *module)
Definition demosaic.c:1999
static __DT_CLONE_TARGETS__ void _downsample_guided_laplacian_fit(const float *const restrict HF, float *const restrict coeff, float *const restrict bias, const size_t width, const size_t height)
Fit one local affine RGB model for the current high-frequency scale.
Definition demosaic.c:658
#define BAYER_SNAPPER
Definition demosaic.c:105
int default_colorspace(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece)
Definition demosaic.c:324
void input_format(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece, dt_iop_buffer_dsc_t *dsc)
Definition demosaic.c:365
int flags()
Definition demosaic.c:319
static __DT_CLONE_TARGETS__ float _downsample_xtrans_missing_colour(const float *const in, const dt_iop_roi_t *const roi_in, const int px, const int py, const uint8_t(*const xtrans)[6], const int colour)
Reconstruct one missing X-Trans colour from the nearest surrounding photosites.
Definition demosaic.c:520
#define DOWNSAMPLE_GUIDED_SCALES
Definition demosaic.c:106
__DT_CLONE_TARGETS__ int process(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, const void *const i, void *const o)
Definition demosaic.c:982
gboolean force_enable(struct dt_iop_module_t *self, const gboolean current_state)
Definition demosaic.c:2066
void cleanup_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Definition demosaic.c:2218
static void _visualize_callback(GtkWidget *quad, gpointer user_data)
Definition demosaic.c:2306
void init_global(dt_iop_module_so_t *module)
Definition demosaic.c:1921
int process_cl(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, cl_mem dev_in, cl_mem dev_out)
Definition demosaic.c:1608
void modify_roi_in(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe, struct dt_dev_pixelpipe_iop_t *piece, const dt_iop_roi_t *roi_out, dt_iop_roi_t *roi_in)
Definition demosaic.c:935
int legacy_params(dt_iop_module_t *self, const void *const old_params, const int old_version, void *new_params, const int new_version)
Definition demosaic.c:329
#define XTRANS_SNAPPER
Definition demosaic.c:104
void dt_iop_params_t
Definition dev_history.h:41
#define dt_dev_pixelpipe_update_history_main(dev)
@ DT_DEV_PIXELPIPE_DISPLAY_PASSTHRU_MONO
Definition develop.h:137
@ DT_DEV_PIXELPIPE_DISPLAY_PASSTHRU
Definition develop.h:136
void dtgtk_cairo_paint_showmask(cairo_t *cr, gint x, gint y, gint w, gint h, gint flags, void *data)
static __DT_CLONE_TARGETS__ int dual_demosaic(const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, float *const restrict rgb_data, const float *const restrict raw_data, dt_iop_roi_t *const roi_out, const dt_iop_roi_t *const roi_in, const uint32_t filters, const uint8_t(*const xtrans)[6], const gboolean dual_mask, float dual_threshold)
Definition dual.c:39
gboolean dual_demosaic_cl(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, cl_mem detail, cl_mem blend, cl_mem high_image, cl_mem low_image, cl_mem out, const int width, const int height, const int showmask)
Definition dual.c:115
void default_input_format(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece, dt_iop_buffer_dsc_t *dsc)
Definition format.c:57
void dt_iop_buffer_dsc_update_bpp(dt_iop_buffer_dsc_t *dsc)
Definition format.c:28
@ TYPE_FLOAT
Definition format.h:46
#define DT_GUI_BOX_SPACING
Definition gtk.h:109
static GtkWidget * dt_ui_label_new(const gchar *str)
Definition gtk.h:461
@ DT_IMAGE_MONOCHROME_BAYER
Definition image.h:138
@ DT_IMAGE_4BAYER
Definition image.h:127
dt_image_t * dt_image_cache_get(dt_image_cache_t *cache, const int32_t imgid, char mode)
void dt_image_cache_write_release(dt_image_cache_t *cache, dt_image_t *img, dt_image_cache_write_mode_t mode)
@ DT_IMAGE_CACHE_RELAXED
Definition image_cache.h:51
static void dt_iop_image_copy_by_size(float *const __restrict__ out, const float *const __restrict__ in, const size_t width, const size_t height, const size_t ch)
Definition imagebuf.h:87
const char ** dt_iop_set_description(dt_iop_module_t *module, const char *main_text, const char *purpose, const char *input, const char *process, const char *output)
Definition imageop.c:3141
#define dt_omploop_sfence()
Definition imageop.h:702
#define dt_iop_fmt_log(module, fmt,...)
Debug helper to trace a module's input-format-driven decisions on the -d pipe channel (DT_DEBUG_PIPE)...
Definition imageop.h:453
@ IOP_FLAGS_ALLOW_TILING
Definition imageop.h:169
@ IOP_FLAGS_ONE_INSTANCE
Definition imageop.h:172
@ IOP_GROUP_TECHNICAL
Definition imageop.h:143
#define IOP_GUI_ALLOC(module)
Definition imageop.h:599
GtkWidget * dt_bauhaus_slider_from_params(dt_iop_module_t *self, const char *param)
Definition imageop_gui.c:77
GtkWidget * dt_bauhaus_combobox_from_params(dt_iop_module_t *self, const char *param)
int dt_iop_clip_and_zoom_roi_cl(int devid, cl_mem dev_out, cl_mem dev_in, const dt_iop_roi_t *const roi_out, const dt_iop_roi_t *const roi_in)
const struct dt_interpolation * dt_interpolation_new(enum dt_interpolation_type type)
void dt_interpolation_resample_roi_1c(const struct dt_interpolation *itor, float *out, const dt_iop_roi_t *const roi_out, const float *const in, const dt_iop_roi_t *const roi_in)
@ DT_INTERPOLATION_USERPREF
static const float x
const float *const const float coeff[3]
#define LMMSE_GRP
Definition lmmse.c:52
static void lmmse_demosaic(const dt_dev_pixelpipe_iop_t *piece, float *const restrict out, const float *const restrict in, dt_iop_roi_t *const roi_out, const dt_iop_roi_t *const roi_in, const uint32_t filters, const uint32_t mode, float *const restrict gamma_in, float *const restrict gamma_out)
Definition lmmse.c:129
float *const restrict const size_t k
static int process_markesteijn_cl(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, cl_mem dev_in, cl_mem dev_out, const dt_iop_roi_t *const roi_in, const dt_iop_roi_t *const roi_out, const gboolean smooth)
static __DT_CLONE_TARGETS__ void xtrans_markesteijn_interpolate(float *out, const float *const in, const dt_iop_roi_t *const roi_out, const dt_iop_roi_t *const roi_in, const uint8_t(*const xtrans)[6], const int passes)
Definition markesteijn.c:47
static __DT_CLONE_TARGETS__ void xtrans_fdc_interpolate(struct dt_iop_module_t *self, float *out, const float *const in, const dt_iop_roi_t *const roi_out, const dt_iop_roi_t *const roi_in, const uint8_t(*const xtrans)[6])
float dt_aligned_pixel_t[4]
int dt_opencl_local_buffer_opt(const int devid, const int kernel, dt_opencl_local_buffer_t *factors)
Definition opencl.c:3156
int dt_opencl_enqueue_kernel_2d(const int dev, const int kernel, const size_t *sizes)
Definition opencl.c:2136
void * dt_opencl_alloc_device_buffer(const int devid, const size_t size)
Definition opencl.c:2544
void * dt_opencl_alloc_device(const int devid, const int width, const int height, const int bpp)
Definition opencl.c:2471
int dt_opencl_create_kernel(const int prog, const char *name)
Definition opencl.c:2030
void * dt_opencl_copy_host_to_device_constant(const int devid, const size_t size, void *host)
Definition opencl.c:2332
void dt_opencl_free_kernel(const int kernel)
Definition opencl.c:2073
int dt_opencl_set_kernel_arg(const int dev, const int kernel, const int num, const size_t size, const void *arg)
Definition opencl.c:2127
int dt_opencl_enqueue_kernel_2d_with_local(const int dev, const int kernel, const size_t *sizes, const size_t *local)
Definition opencl.c:2142
void dt_opencl_release_mem_object(cl_mem mem)
Definition opencl.c:2383
#define DT_OPENCL_DEFAULT_ERROR
Definition opencl.h:57
#define ROUNDUP(a, n)
Definition opencl.h:78
#define ROUNDUPDHT(a, b)
Definition opencl.h:82
#define ROUNDUPDWD(a, b)
Definition opencl.h:81
static __DT_CLONE_TARGETS__ void passthrough_monochrome(float *out, const float *const in, dt_iop_roi_t *const roi_out, const dt_iop_roi_t *const roi_in)
Definition passthrough.c:22
static __DT_CLONE_TARGETS__ void passthrough_color(float *out, const float *const in, dt_iop_roi_t *const roi_out, const dt_iop_roi_t *const roi_in, const uint32_t filters, const uint8_t(*const xtrans)[6])
Definition passthrough.c:44
@ DT_DEV_PIXELPIPE_FULL
Definition pixelpipe.h:39
static __DT_CLONE_TARGETS__ int demosaic_ppg(float *const out, const float *const in, const dt_iop_roi_t *const roi_out, const dt_iop_roi_t *const roi_in, const uint32_t filters, const float thrs)
Definition ppg.c:22
static int process_rcd_cl(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, cl_mem dev_in, cl_mem dev_out, const dt_iop_roi_t *const roi_in, const dt_iop_roi_t *const roi_out, const gboolean smooth)
Definition rcd.c:568
#define RCD_TILESIZE
Definition rcd.c:54
#define eps
Definition rcd.c:81
static void rcd_demosaic(const dt_dev_pixelpipe_iop_t *piece, float *const restrict out, const float *const restrict in, dt_iop_roi_t *const roi_out, const dt_iop_roi_t *const roi_in, const uint32_t filters)
Definition rcd.c:274
struct _GtkWidget GtkWidget
Definition splash.h:29
const float uint32_t state[4]
int32_t num_openmp_threads
Definition darktable.h:758
struct dt_gui_gtk_t * gui
Definition darktable.h:775
int32_t unmuted
Definition darktable.h:760
struct dt_image_cache_t * image_cache
Definition darktable.h:777
dt_iop_buffer_dsc_t dsc_in
struct dt_iop_module_t *void * data
dt_dev_pixelpipe_type_t type
int32_t gui_attached
Definition develop.h:162
dt_image_t image_storage
Definition develop.h:259
int32_t reset
Definition gtk.h:172
char camera_makermodel[128]
Definition image.h:300
float exif_iso
Definition image.h:288
int32_t flags
Definition image.h:319
float d65_color_matrix[9]
Definition image.h:339
dt_iop_buffer_dsc_t dsc
Definition image.h:337
float adobe_XYZ_to_CAM[4][3]
Definition image.h:362
int32_t id
Definition image.h:319
uint32_t filters
Definition format.h:60
unsigned int channels
Definition format.h:54
uint8_t xtrans[6][6]
Definition format.h:70
dt_iop_buffer_type_t datatype
Definition format.h:56
dt_aligned_pixel_t processed_maximum
Definition format.h:85
uint32_t demosaicing_method
Definition demosaic.c:231
double CAM_to_RGB[3][4]
Definition demosaic.c:234
GtkWidget * demosaic_method_xtrans
Definition demosaic.c:272
GtkWidget * color_smoothing
Definition demosaic.c:270
GtkWidget * demosaic_method_bayer
Definition demosaic.c:271
dt_iop_demosaic_method_t demosaicing_method
Definition demosaic.c:261
dt_iop_demosaic_greeneq_t green_eq
Definition demosaic.c:258
dt_iop_demosaic_smooth_t color_smoothing
Definition demosaic.c:260
dt_iop_demosaic_lmmse_t lmmse_refine
Definition demosaic.c:262
dt_iop_global_data_t * data
Definition imageop.h:233
dt_iop_params_t * default_params
Definition imageop.h:307
GtkWidget * widget
Definition imageop.h:337
struct dt_develop_t * dev
Definition imageop.h:296
dt_iop_gui_data_t * gui_data
Definition imageop.h:311
gboolean default_enabled
Definition imageop.h:303
dt_iop_global_data_t * global_data
Definition imageop.h:314
dt_iop_params_t * params
Definition imageop.h:307
Region of interest passed through the pixelpipe.
Definition imageop.h:72
double scale
Definition imageop.h:74
double clock
Definition darktable.h:842
double user
Definition darktable.h:843
typedef double((*spd)(unsigned long int wavelength, double TempK))
#define MIN(a, b)
Definition thinplate.c:32
#define MAX(a, b)
Definition thinplate.c:29
static int process_vng_cl(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, cl_mem dev_in, cl_mem dev_out, const dt_iop_roi_t *const roi_in, const dt_iop_roi_t *const roi_out, const gboolean smooth, const int only_vng_linear)
Definition vng.c:206
static __DT_CLONE_TARGETS__ int vng_interpolate(float *out, const float *const in, const dt_iop_roi_t *const roi_out, const dt_iop_roi_t *const roi_in, const uint32_t filters, const uint8_t(*const xtrans)[6], const int only_vng_linear)
Definition vng.c:34