Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
dual.c
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2021-2022 Hanno Schwalm.
4 Copyright (C) 2021 luzpaz.
5 Copyright (C) 2021 Marco.
6 Copyright (C) 2021 Pascal Obry.
7 Copyright (C) 2021 Ralf Brown.
8 Copyright (C) 2022 Martin Bařinka.
9 Copyright (C) 2023, 2026 Aurélien PIERRE.
10
11 darktable is free software: you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation, either version 3 of the License, or
14 (at your option) any later version.
15
16 darktable is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with darktable. If not, see <http://www.gnu.org/licenses/>.
23*/
24
25/*
26 Dual demosaicing has been implemented by Ingo Weyrich <heckflosse67@gmx.de> for
27 rawtherapee under GNU General Public License Version 3
28 and has been modified to work for darktable by Hanno Schwalm (hanno@schwalm-bremen.de).
29 Also the code for dt_masks_blur_9x9 has been taken from rawtherapee capturesharpening,
30 implemented also by Ingo Weyrich.
31*/
32
33
34static float slider2contrast(float slider)
35{
36 return 0.005f * powf(slider, 1.1f);
37}
40 float *const restrict rgb_data, const float *const restrict raw_data,
41 dt_iop_roi_t *const roi_out, const dt_iop_roi_t *const roi_in,
42 const uint32_t filters, const uint8_t (*const xtrans)[6],
43 const gboolean dual_mask, float dual_threshold)
44{
45 const int width = roi_in->width;
46 const int height = roi_in->height;
47 if((width < 16) || (height < 16)) return 0;
48
49 // If the threshold is zero and we don't want to see the blend mask we don't do anything
50 if(dual_threshold <= 0.0f) return 0;
51
52 float *blend = dt_pixelpipe_cache_alloc_align_float((size_t) width * height, pipe);
53 float *tmp = dt_pixelpipe_cache_alloc_align_float((size_t) width * height, pipe);
54 float *vng_image = dt_pixelpipe_cache_alloc_align_float((size_t) 4 * width * height, pipe);
55 if(IS_NULL_PTR(blend) || IS_NULL_PTR(tmp) || IS_NULL_PTR(vng_image))
56 {
60 dt_control_alert(_("Not enough memory"), _("[dual demosaic] can't allocate internal buffers"),
62 return 1;
63 }
64 const gboolean info = ((dt_get_debug_flags() & (DT_DEBUG_DEMOSAIC | DT_DEBUG_PERF))
66
67 if(vng_interpolate(vng_image, raw_data, roi_out, roi_in, filters, xtrans, FALSE))
68 {
72 return 1;
73 }
74 color_smoothing(vng_image, roi_out, 2);
75
76 dt_times_t start_blend = { 0 }, end_blend = { 0 };
77 if(info) dt_get_times(&start_blend);
78
79 const float contrastf = slider2contrast(dual_threshold);
80
81 dt_masks_calc_rawdetail_mask(rgb_data, blend, tmp, width, height, piece->dsc_in.temperature.coeffs);
82 dt_masks_calc_detail_mask(blend, blend, tmp, width, height, contrastf, TRUE);
83
84 if(dual_mask)
85 {
87 __OMP_FOR_SIMD__(aligned(blend, vng_image, rgb_data : 64))
88 for(int idx = 0; idx < width * height; idx++)
89 {
90 for(int c = 0; c < 4; c++)
91 rgb_data[idx * 4 + c] = blend[idx];
92 }
93 }
94 else
95 {
96 __OMP_FOR_SIMD__(aligned(blend, vng_image, rgb_data : 64))
97 for(int idx = 0; idx < width * height; idx++)
98 {
99 const int oidx = 4 * idx;
100 for(int c = 0; c < 4; c++)
101 rgb_data[oidx + c] = intp(blend[idx], rgb_data[oidx + c], vng_image[oidx + c]);
102 }
103 }
104 if(info)
105 {
106 dt_get_times(&end_blend);
107 fprintf(stderr," [demosaic] CPU dual blending %.4f secs (%.4f CPU)\n", end_blend.clock - start_blend.clock, end_blend.user - start_blend.user);
108 }
112 return 0;
113}
114
115#ifdef HAVE_OPENCL
117 const dt_dev_pixelpipe_iop_t *piece, cl_mem detail, cl_mem blend,
118 cl_mem high_image, cl_mem low_image, cl_mem out, const int width,
119 const int height, const int showmask)
120{
121 const int devid = pipe->devid;
124
125 const float contrastf = slider2contrast(data->dual_thrs);
126 if(showmask)
128
129 {
130 size_t sizes[3] = { ROUNDUPDWD(width, devid), ROUNDUPDHT(height, devid), 1 };
131 const dt_aligned_pixel_t wb = { piece->dsc_in.temperature.coeffs[0], piece->dsc_in.temperature.coeffs[1],
132 piece->dsc_in.temperature.coeffs[2] };
134 dt_opencl_set_kernel_arg(devid, kernel, 0, sizeof(cl_mem), &detail);
135 dt_opencl_set_kernel_arg(devid, kernel, 1, sizeof(cl_mem), &high_image);
136 dt_opencl_set_kernel_arg(devid, kernel, 2, sizeof(int), &width);
137 dt_opencl_set_kernel_arg(devid, kernel, 3, sizeof(int), &height);
138 dt_opencl_set_kernel_arg(devid, kernel, 4, sizeof(float), &wb[0]);
139 dt_opencl_set_kernel_arg(devid, kernel, 5, sizeof(float), &wb[1]);
140 dt_opencl_set_kernel_arg(devid, kernel, 6, sizeof(float), &wb[2]);
141 const int err = dt_opencl_enqueue_kernel_2d(devid, kernel, sizes);
142 if(err != CL_SUCCESS) return FALSE;
143 }
144
145 {
146 size_t sizes[3] = { ROUNDUPDWD(width, devid), ROUNDUPDHT(height, devid), 1 };
148 dt_opencl_set_kernel_arg(devid, kernel, 0, sizeof(cl_mem), &detail);
149 dt_opencl_set_kernel_arg(devid, kernel, 1, sizeof(cl_mem), &blend);
150 dt_opencl_set_kernel_arg(devid, kernel, 2, sizeof(int), &width);
151 dt_opencl_set_kernel_arg(devid, kernel, 3, sizeof(int), &height);
152 const int err = dt_opencl_enqueue_kernel_2d(devid, kernel, sizes);
153 if(err != CL_SUCCESS) return FALSE;
154 }
155
156 {
157 const int flag = 1;
158 size_t sizes[3] = { ROUNDUPDWD(width, devid), ROUNDUPDHT(height, devid), 1 };
160 dt_opencl_set_kernel_arg(devid, kernel, 0, sizeof(cl_mem), &blend);
161 dt_opencl_set_kernel_arg(devid, kernel, 1, sizeof(cl_mem), &detail);
162 dt_opencl_set_kernel_arg(devid, kernel, 2, sizeof(int), &width);
163 dt_opencl_set_kernel_arg(devid, kernel, 3, sizeof(int), &height);
164 dt_opencl_set_kernel_arg(devid, kernel, 4, sizeof(float), &contrastf);
165 dt_opencl_set_kernel_arg(devid, kernel, 5, sizeof(int), &flag);
166 const int err = dt_opencl_enqueue_kernel_2d(devid, kernel, sizes);
167 if(err != CL_SUCCESS) return FALSE;
168 }
169
170 {
171 float blurmat[13];
172 dt_masks_blur_9x9_coeff(blurmat, 2.0f);
173 cl_mem dev_blurmat = NULL;
174 dev_blurmat = dt_opencl_copy_host_to_device_constant(devid, sizeof(float) * 13, blurmat);
175 if(!IS_NULL_PTR(dev_blurmat))
176 {
177 size_t sizes[3] = { ROUNDUPDWD(width, devid), ROUNDUPDHT(height, devid), 1 };
178 const int clkernel = dt_develop_blend_get_cl_global()->kernel_mask_blur;
179 dt_opencl_set_kernel_arg(devid, clkernel, 0, sizeof(cl_mem), &detail);
180 dt_opencl_set_kernel_arg(devid, clkernel, 1, sizeof(cl_mem), &blend);
181 dt_opencl_set_kernel_arg(devid, clkernel, 2, sizeof(int), &width);
182 dt_opencl_set_kernel_arg(devid, clkernel, 3, sizeof(int), &height);
183 dt_opencl_set_kernel_arg(devid, clkernel, 4, sizeof(cl_mem), (void *) &dev_blurmat);
184 const int err = dt_opencl_enqueue_kernel_2d(devid, clkernel, sizes);
185 dt_opencl_release_mem_object(dev_blurmat);
186 if(err != CL_SUCCESS) return FALSE;
187 }
188 else
189 {
190 dt_opencl_release_mem_object(dev_blurmat);
191 return FALSE;
192 }
193 }
194
195 {
196 size_t sizes[3] = { ROUNDUPDWD(width, devid), ROUNDUPDHT(height, devid), 1 };
197 dt_opencl_set_kernel_arg(devid, gd->kernel_write_blended_dual, 0, sizeof(cl_mem), &high_image);
198 dt_opencl_set_kernel_arg(devid, gd->kernel_write_blended_dual, 1, sizeof(cl_mem), &low_image);
199 dt_opencl_set_kernel_arg(devid, gd->kernel_write_blended_dual, 2, sizeof(cl_mem), &out);
200 dt_opencl_set_kernel_arg(devid, gd->kernel_write_blended_dual, 3, sizeof(int), &width);
201 dt_opencl_set_kernel_arg(devid, gd->kernel_write_blended_dual, 4, sizeof(int), &height);
202 dt_opencl_set_kernel_arg(devid, gd->kernel_write_blended_dual, 5, sizeof(cl_mem), &blend);
203 dt_opencl_set_kernel_arg(devid, gd->kernel_write_blended_dual, 6, sizeof(int), &showmask);
204 const int err = dt_opencl_enqueue_kernel_2d(devid, gd->kernel_write_blended_dual, sizes);
205 if(err != CL_SUCCESS) return FALSE;
206 }
207
208 return TRUE;
209}
210#endif
211
212// clang-format off
213// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
214// vim: shiftwidth=2 expandtab tabstop=2 cindent
215// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
216// clang-format on
#define TRUE
Definition ashift_lsd.c:162
#define FALSE
Definition ashift_lsd.c:158
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
dt_blendop_cl_global_t * dt_develop_blend_get_cl_global(void)
Definition blend.c:72
static float intp(const float a, const float b, const float c)
Definition cacorrect.c:185
const dt_colormatrix_t dt_aligned_pixel_t out
void dt_control_alert(const char *title, const char *message, const char *item)
Tell the user something that must not go unseen: what it says stays true after a toast would have fad...
Definition control.c:883
__DT_CLONE_TARGETS__ void dt_masks_calc_rawdetail_mask(float *const restrict src, float *const restrict mask, float *const restrict tmp, const int width, const int height, const dt_aligned_pixel_t wb)
Definition detail.c:289
void dt_masks_blur_9x9_coeff(float *c, const float sigma)
Definition detail.c:165
void dt_masks_calc_detail_mask(float *const restrict src, float *const restrict out, float *const restrict tmp, const int width, const int height, const float threshold, const gboolean detail)
Definition detail.c:331
@ DT_DEV_PIXELPIPE_DISPLAY_PASSTHRU
Definition develop.h:141
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
static float slider2contrast(float slider)
Definition dual.c:34
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:116
const char flag
Definition image.h:320
static float kernel(const float *x, const float *y)
static const dt_dev_pixelpipe_t * pipe
Definition layers.h:49
static const dt_dev_pixelpipe_t const dt_dev_pixelpipe_iop_t * piece
Definition layers.h:50
@ DT_DEBUG_DEMOSAIC
Definition logging.h:72
@ DT_DEBUG_PERF
Definition logging.h:55
int32_t dt_get_debug_flags(void)
Definition darktable.c:2094
#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 macros.h:96
uint32_t width
Definition mipmap_cache.c:0
uint32_t height
Definition mipmap_cache.c:1
int dt_opencl_enqueue_kernel_2d(const int dev, const int kernel, const size_t *sizes)
Definition opencl.c:2612
void * dt_opencl_copy_host_to_device_constant(const int devid, const size_t size, void *host)
Definition opencl.c:2808
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:2603
void dt_opencl_release_mem_object(cl_mem mem)
Definition opencl.c:2863
#define ROUNDUPDHT(a, b)
Definition opencl.h:86
#define ROUNDUPDWD(a, b)
Definition opencl.h:85
#define __OMP_FOR_SIMD__(...)
Definition openmp.h:97
@ DT_DEV_PIXELPIPE_FULL
Definition pixelpipe.h:43
#define dt_pixelpipe_cache_free_align(mem)
#define dt_pixelpipe_cache_alloc_align_float(pixels, pipe)
DT_ALIGNED_PIXEL float dt_aligned_pixel_t[4]
Definition simd.h:53
dt_dev_pixelpipe_type_t type
struct dt_develop_t * dev
dt_image_t image_storage
Definition develop.h:225
char fullpath[DT_PATH_MAX]
Definition image.h:396
dt_iop_global_data_t * global_data
Definition imageop.h:337
Region of interest passed through the pixelpipe.
Definition format.h:49
int width
Definition format.h:50
int height
Definition format.h:50
double clock
Definition times.h:39
double user
Definition times.h:40
#define __DT_CLONE_TARGETS__
static void dt_get_times(dt_times_t *t)
Definition times.h:50
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