Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
vng.c
Go to the documentation of this file.
1/*
2 This file is part of the Ansel project.
3 Copyright (C) 2023, 2025-2026 Aurélien PIERRE.
4 Copyright (C) 2024 Alynx Zhou.
5
6 Ansel is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 Ansel is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with Ansel. If not, see <http://www.gnu.org/licenses/>.
18*/
19
20
21// VNG interpolate adapted from dcraw 9.20
22
23/*
24 This algorithm is officially called:
25
26 "Interpolation using a Threshold-based variable number of gradients"
27
28 described in http://scien.stanford.edu/pages/labsite/1999/psych221/projects/99/tingchen/algodep/vargra.html
29
30 I've extended the basic idea to work with non-Bayer filter arrays.
31 Gradients are numbered clockwise from NW=0 to W=7.
32 */
34static int vng_interpolate(float *out, const float *const in,
35 const dt_iop_roi_t *const roi_out, const dt_iop_roi_t *const roi_in,
36 const uint32_t filters, const uint8_t (*const xtrans)[6], const int only_vng_linear)
37{
38 static const signed char terms[]
39 = { -2, -2, +0, -1, 1, 0x01, -2, -2, +0, +0, 2, 0x01, -2, -1, -1, +0, 1, 0x01, -2, -1, +0, -1, 1, 0x02,
40 -2, -1, +0, +0, 1, 0x03, -2, -1, +0, +1, 2, 0x01, -2, +0, +0, -1, 1, 0x06, -2, +0, +0, +0, 2, 0x02,
41 -2, +0, +0, +1, 1, 0x03, -2, +1, -1, +0, 1, 0x04, -2, +1, +0, -1, 2, 0x04, -2, +1, +0, +0, 1, 0x06,
42 -2, +1, +0, +1, 1, 0x02, -2, +2, +0, +0, 2, 0x04, -2, +2, +0, +1, 1, 0x04, -1, -2, -1, +0, 1, 0x80,
43 -1, -2, +0, -1, 1, 0x01, -1, -2, +1, -1, 1, 0x01, -1, -2, +1, +0, 2, 0x01, -1, -1, -1, +1, 1, 0x88,
44 -1, -1, +1, -2, 1, 0x40, -1, -1, +1, -1, 1, 0x22, -1, -1, +1, +0, 1, 0x33, -1, -1, +1, +1, 2, 0x11,
45 -1, +0, -1, +2, 1, 0x08, -1, +0, +0, -1, 1, 0x44, -1, +0, +0, +1, 1, 0x11, -1, +0, +1, -2, 2, 0x40,
46 -1, +0, +1, -1, 1, 0x66, -1, +0, +1, +0, 2, 0x22, -1, +0, +1, +1, 1, 0x33, -1, +0, +1, +2, 2, 0x10,
47 -1, +1, +1, -1, 2, 0x44, -1, +1, +1, +0, 1, 0x66, -1, +1, +1, +1, 1, 0x22, -1, +1, +1, +2, 1, 0x10,
48 -1, +2, +0, +1, 1, 0x04, -1, +2, +1, +0, 2, 0x04, -1, +2, +1, +1, 1, 0x04, +0, -2, +0, +0, 2, 0x80,
49 +0, -1, +0, +1, 2, 0x88, +0, -1, +1, -2, 1, 0x40, +0, -1, +1, +0, 1, 0x11, +0, -1, +2, -2, 1, 0x40,
50 +0, -1, +2, -1, 1, 0x20, +0, -1, +2, +0, 1, 0x30, +0, -1, +2, +1, 2, 0x10, +0, +0, +0, +2, 2, 0x08,
51 +0, +0, +2, -2, 2, 0x40, +0, +0, +2, -1, 1, 0x60, +0, +0, +2, +0, 2, 0x20, +0, +0, +2, +1, 1, 0x30,
52 +0, +0, +2, +2, 2, 0x10, +0, +1, +1, +0, 1, 0x44, +0, +1, +1, +2, 1, 0x10, +0, +1, +2, -1, 2, 0x40,
53 +0, +1, +2, +0, 1, 0x60, +0, +1, +2, +1, 1, 0x20, +0, +1, +2, +2, 1, 0x10, +1, -2, +1, +0, 1, 0x80,
54 +1, -1, +1, +1, 1, 0x88, +1, +0, +1, +2, 1, 0x08, +1, +0, +2, -1, 1, 0x40, +1, +0, +2, +1, 1, 0x10 };
55 static const signed char chood[]
56 = { -1, -1, -1, 0, -1, +1, 0, +1, +1, +1, +1, 0, +1, -1, 0, -1 };
57 int *ip, *code[16][16];
58 // ring buffer pointing to three most recent rows processed (brow[3]
59 // is only used for rotating the buffer
60 float(*brow[4])[4];
61 const int width = roi_out->width, height = roi_out->height;
62 const int prow = (filters == 9) ? 6 : 8;
63 const int pcol = (filters == 9) ? 6 : 2;
64 const int colors = (filters == 9) ? 3 : 4;
65
66 // separate out G1 and G2 in RGGB Bayer patterns
67 uint32_t filters4 = filters;
68 if(filters == 9 || FILTERS_ARE_4BAYER(filters)) // x-trans or CYGM/RGBE
69 filters4 = filters;
70 else if((filters & 3) == 1)
71 filters4 = filters | 0x03030303u;
72 else
73 filters4 = filters | 0x0c0c0c0cu;
74
75 lin_interpolate(out, in, roi_out, roi_in, filters4, xtrans);
76
77 // if only linear interpolation is requested we can stop it here
78 if(only_vng_linear) return 0;
79
80 char *buffer = (char *)dt_pixelpipe_cache_alloc_align_cache(
81 sizeof(**brow) * width * 3 + sizeof(*ip) * prow * pcol * 320,
82 0);
83 if(IS_NULL_PTR(buffer))
84 {
85 fprintf(stderr, "[demosaic] not able to allocate VNG buffer\n");
86 return 1;
87 }
88 for(int row = 0; row < 3; row++) brow[row] = (float(*)[4])buffer + row * width;
89 ip = (int *)(buffer + sizeof(**brow) * width * 3);
90
91 for(int row = 0; row < prow; row++) /* Precalculate for VNG */
92 for(int col = 0; col < pcol; col++)
93 {
94 code[row][col] = ip;
95 const signed char *cp = terms;
96 for(int t = 0; t < 64; t++)
97 {
98 const int y1 = *cp++, x1 = *cp++;
99 const int y2 = *cp++, x2 = *cp++;
100 const int weight = *cp++;
101 const int grads = *cp++;
102 const int color = fcol(row + y1, col + x1, filters4, xtrans);
103 if(fcol(row + y2, col + x2, filters4, xtrans) != color) continue;
104 const int diag
105 = (fcol(row, col + 1, filters4, xtrans) == color && fcol(row + 1, col, filters4, xtrans) == color)
106 ? 2
107 : 1;
108 if(abs(y1 - y2) == diag && abs(x1 - x2) == diag) continue;
109 *ip++ = (y1 * width + x1) * 4 + color;
110 *ip++ = (y2 * width + x2) * 4 + color;
111 *ip++ = weight;
112 for(int g = 0; g < 8; g++)
113 if(grads & 1 << g) *ip++ = g;
114 *ip++ = -1;
115 }
116 *ip++ = INT_MAX;
117 cp = chood;
118 for(int g = 0; g < 8; g++)
119 {
120 const int y = *cp++, x = *cp++;
121 *ip++ = (y * width + x) * 4;
122 const int color = fcol(row, col, filters4, xtrans);
123 if(fcol(row + y, col + x, filters4, xtrans) != color
124 && fcol(row + y * 2, col + x * 2, filters4, xtrans) == color)
125 *ip++ = (y * width + x) * 8 + color;
126 else
127 *ip++ = 0;
128 }
129 }
130
131 for(int row = 2; row < height - 2; row++) /* Do VNG interpolation */
132 {
133 __OMP_PARALLEL_FOR__(private(ip) )
134 for(int col = 2; col < width - 2; col++)
135 {
136 int g;
137 float gval[8] = { 0.0f };
138 float *pix = out + 4 * (row * width + col);
139 ip = code[(row + roi_in->y) % prow][(col + roi_in->x) % pcol];
140 while((g = ip[0]) != INT_MAX) /* Calculate gradients */
141 {
142 float diff = fabsf(pix[g] - pix[ip[1]]) * ip[2];
143 gval[ip[3]] += diff;
144 ip += 5;
145 if((g = ip[-1]) == -1) continue;
146 gval[g] += diff;
147 while((g = *ip++) != -1) gval[g] += diff;
148 }
149 ip++;
150 float gmin = gval[0], gmax = gval[0]; /* Choose a threshold */
151 for(g = 1; g < 8; g++)
152 {
153 if(gmin > gval[g]) gmin = gval[g];
154 if(gmax < gval[g]) gmax = gval[g];
155 }
156 if(gmax == 0)
157 {
158 memcpy(brow[2][col], pix, sizeof(*out) * 4);
159 continue;
160 }
161 const float thold = gmin + (gmax * 0.5f);
162 dt_aligned_pixel_t sum = { 0.0f };
163 const int color = fcol(row + roi_in->y, col + roi_in->x, filters4, xtrans);
164 int num = 0;
165 for(g = 0; g < 8; g++, ip += 2) /* Average the neighbors */
166 {
167 if(gval[g] <= thold)
168 {
169 for(int c = 0; c < colors; c++)
170 if(c == color && ip[1])
171 sum[c] += (pix[c] + pix[ip[1]]) * 0.5f;
172 else
173 sum[c] += pix[ip[0] + c];
174 num++;
175 }
176 }
177 for(int c = 0; c < colors; c++) /* Save to buffer */
178 {
179 float tot = pix[color];
180 if(c != color) tot += (sum[c] - sum[color]) / num;
181 brow[2][col][c] = tot;
182 }
183 }
184 if(row > 3) /* Write buffer to image */
185 memcpy(out + 4 * ((row - 2) * width + 2), brow[0] + 2, sizeof(*out) * 4 * (width - 4));
186 // rotate ring buffer
187 for(int g = 0; g < 4; g++) brow[(g - 1) & 3] = brow[g];
188 }
189 // copy the final two rows to the image
190 memcpy(out + (4 * ((height - 4) * width + 2)), brow[0] + 2, sizeof(*out) * 4 * (width - 4));
191 memcpy(out + (4 * ((height - 3) * width + 2)), brow[1] + 2, sizeof(*out) * 4 * (width - 4));
193
194 if(filters != 9 && !FILTERS_ARE_4BAYER(filters)) // x-trans or CYGM/RGBE
195// for Bayer mix the two greens to make VNG4
197 for(int i = 0; i < height * width; i++)
198 out[i * 4 + 1] = (out[i * 4 + 1] + out[i * 4 + 3]) / 2.0f;
199
200
201 return 0;
202}
203
204#ifdef HAVE_OPENCL
205
206static int process_vng_cl(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe,
207 const dt_dev_pixelpipe_iop_t *piece, cl_mem dev_in, cl_mem dev_out,
208 const dt_iop_roi_t *const roi_in, const dt_iop_roi_t *const roi_out,
209 const gboolean smooth, const int only_vng_linear)
210{
213
214 const uint8_t(*const xtrans)[6] = (const uint8_t(*const)[6])piece->dsc_in.xtrans;
215
216 // separate out G1 and G2 in Bayer patterns
217 uint32_t filters4;
218 if(piece->dsc_in.filters == 9u)
219 filters4 = piece->dsc_in.filters;
220 else if((piece->dsc_in.filters & 3) == 1)
221 filters4 = piece->dsc_in.filters | 0x03030303u;
222 else
223 filters4 = piece->dsc_in.filters | 0x0c0c0c0cu;
224
225 const int size = (filters4 == 9u) ? 6 : 16;
226 const int colors = (filters4 == 9u) ? 3 : 4;
227 const int prow = (filters4 == 9u) ? 6 : 8;
228 const int pcol = (filters4 == 9u) ? 6 : 2;
229 const int devid = pipe->devid;
230
231 const float processed_maximum[4]
232 = { piece->dsc_in.processed_maximum[0], piece->dsc_in.processed_maximum[1],
233 piece->dsc_in.processed_maximum[2], 1.0f };
234
235 int *ips = NULL;
236
237 cl_mem dev_tmp = NULL;
238 cl_mem dev_aux = NULL;
239 cl_mem dev_xtrans = NULL;
240 cl_mem dev_lookup = NULL;
241 cl_mem dev_code = NULL;
242 cl_mem dev_ips = NULL;
243 cl_mem dev_green_eq = NULL;
244 cl_int err = -999;
245
246 int32_t(*lookup)[16][32] = NULL;
247
248 if(piece->dsc_in.filters == 9u)
249 {
250 dev_xtrans = dt_opencl_copy_host_to_device_constant(devid, sizeof(piece->dsc_in.xtrans), (void *)piece->dsc_in.xtrans);
251 if(IS_NULL_PTR(dev_xtrans)) goto error;
252 }
253
254 // build interpolation lookup table for linear interpolation which for a given offset in the sensor
255 // lists neighboring pixels from which to interpolate:
256 // NUM_PIXELS # of neighboring pixels to read
257 // for (1..NUM_PIXELS):
258 // OFFSET # in bytes from current pixel
259 // WEIGHT # how much weight to give this neighbor
260 // COLOR # sensor color
261 // # weights of adjoining pixels not of this pixel's color
262 // COLORA TOT_WEIGHT
263 // COLORB TOT_WEIGHT
264 // COLORPIX # color of center pixel
265 const size_t lookup_size = (size_t)16 * 16 * 32 * sizeof(int32_t);
266 lookup = malloc(lookup_size);
267
268 for(int row = 0; row < size; row++)
269 for(int col = 0; col < size; col++)
270 {
271 int32_t *ip = &(lookup[row][col][1]);
272 int sum[4] = { 0 };
273 const int f = fcol(row + roi_in->y, col + roi_in->x, filters4, xtrans);
274 // make list of adjoining pixel offsets by weight & color
275 for(int y = -1; y <= 1; y++)
276 for(int x = -1; x <= 1; x++)
277 {
278 const int weight = 1 << ((y == 0) + (x == 0));
279 const int color = fcol(row + y + roi_in->y, col + x + roi_in->x, filters4, xtrans);
280 if(color == f) continue;
281 *ip++ = (y << 16) | (x & 0xffffu);
282 *ip++ = weight;
283 *ip++ = color;
284 sum[color] += weight;
285 }
286 lookup[row][col][0] = (ip - &(lookup[row][col][0])) / 3; /* # of neighboring pixels found */
287 for(int c = 0; c < colors; c++)
288 if(c != f)
289 {
290 *ip++ = c;
291 *ip++ = sum[c];
292 }
293 *ip = f;
294 }
295
296 // Precalculate for VNG
297 static const signed char terms[]
298 = { -2, -2, +0, -1, 1, 0x01, -2, -2, +0, +0, 2, 0x01, -2, -1, -1, +0, 1, 0x01, -2, -1, +0, -1, 1, 0x02,
299 -2, -1, +0, +0, 1, 0x03, -2, -1, +0, +1, 2, 0x01, -2, +0, +0, -1, 1, 0x06, -2, +0, +0, +0, 2, 0x02,
300 -2, +0, +0, +1, 1, 0x03, -2, +1, -1, +0, 1, 0x04, -2, +1, +0, -1, 2, 0x04, -2, +1, +0, +0, 1, 0x06,
301 -2, +1, +0, +1, 1, 0x02, -2, +2, +0, +0, 2, 0x04, -2, +2, +0, +1, 1, 0x04, -1, -2, -1, +0, 1, 0x80,
302 -1, -2, +0, -1, 1, 0x01, -1, -2, +1, -1, 1, 0x01, -1, -2, +1, +0, 2, 0x01, -1, -1, -1, +1, 1, 0x88,
303 -1, -1, +1, -2, 1, 0x40, -1, -1, +1, -1, 1, 0x22, -1, -1, +1, +0, 1, 0x33, -1, -1, +1, +1, 2, 0x11,
304 -1, +0, -1, +2, 1, 0x08, -1, +0, +0, -1, 1, 0x44, -1, +0, +0, +1, 1, 0x11, -1, +0, +1, -2, 2, 0x40,
305 -1, +0, +1, -1, 1, 0x66, -1, +0, +1, +0, 2, 0x22, -1, +0, +1, +1, 1, 0x33, -1, +0, +1, +2, 2, 0x10,
306 -1, +1, +1, -1, 2, 0x44, -1, +1, +1, +0, 1, 0x66, -1, +1, +1, +1, 1, 0x22, -1, +1, +1, +2, 1, 0x10,
307 -1, +2, +0, +1, 1, 0x04, -1, +2, +1, +0, 2, 0x04, -1, +2, +1, +1, 1, 0x04, +0, -2, +0, +0, 2, 0x80,
308 +0, -1, +0, +1, 2, 0x88, +0, -1, +1, -2, 1, 0x40, +0, -1, +1, +0, 1, 0x11, +0, -1, +2, -2, 1, 0x40,
309 +0, -1, +2, -1, 1, 0x20, +0, -1, +2, +0, 1, 0x30, +0, -1, +2, +1, 2, 0x10, +0, +0, +0, +2, 2, 0x08,
310 +0, +0, +2, -2, 2, 0x40, +0, +0, +2, -1, 1, 0x60, +0, +0, +2, +0, 2, 0x20, +0, +0, +2, +1, 1, 0x30,
311 +0, +0, +2, +2, 2, 0x10, +0, +1, +1, +0, 1, 0x44, +0, +1, +1, +2, 1, 0x10, +0, +1, +2, -1, 2, 0x40,
312 +0, +1, +2, +0, 1, 0x60, +0, +1, +2, +1, 1, 0x20, +0, +1, +2, +2, 1, 0x10, +1, -2, +1, +0, 1, 0x80,
313 +1, -1, +1, +1, 1, 0x88, +1, +0, +1, +2, 1, 0x08, +1, +0, +2, -1, 1, 0x40, +1, +0, +2, +1, 1, 0x10 };
314 static const signed char chood[]
315 = { -1, -1, -1, 0, -1, +1, 0, +1, +1, +1, +1, 0, +1, -1, 0, -1 };
316
317 const size_t ips_size = (size_t)prow * pcol * 352 * sizeof(int);
318 ips = malloc(ips_size);
319
320 int *ip = ips;
321 int code[16][16];
322
323 for(int row = 0; row < prow; row++)
324 for(int col = 0; col < pcol; col++)
325 {
326 code[row][col] = ip - ips;
327 const signed char *cp = terms;
328 for(int t = 0; t < 64; t++)
329 {
330 const int y1 = *cp++, x1 = *cp++;
331 const int y2 = *cp++, x2 = *cp++;
332 const int weight = *cp++;
333 const int grads = *cp++;
334 const int color = fcol(row + y1, col + x1, filters4, xtrans);
335 if(fcol(row + y2, col + x2, filters4, xtrans) != color) continue;
336 const int diag
337 = (fcol(row, col + 1, filters4, xtrans) == color && fcol(row + 1, col, filters4, xtrans) == color)
338 ? 2
339 : 1;
340 if(abs(y1 - y2) == diag && abs(x1 - x2) == diag) continue;
341 *ip++ = (y1 << 16) | (x1 & 0xffffu);
342 *ip++ = (y2 << 16) | (x2 & 0xffffu);
343 *ip++ = (color << 16) | (weight & 0xffffu);
344 for(int g = 0; g < 8; g++)
345 if(grads & 1 << g) *ip++ = g;
346 *ip++ = -1;
347 }
348 *ip++ = INT_MAX;
349 cp = chood;
350 for(int g = 0; g < 8; g++)
351 {
352 const int y = *cp++, x = *cp++;
353 *ip++ = (y << 16) | (x & 0xffffu);
354 const int color = fcol(row, col, filters4, xtrans);
355 if(fcol(row + y, col + x, filters4, xtrans) != color
356 && fcol(row + y * 2, col + x * 2, filters4, xtrans) == color)
357 {
358 *ip++ = (2*y << 16) | (2*x & 0xffffu);
359 *ip++ = color;
360 }
361 else
362 {
363 *ip++ = 0;
364 *ip++ = 0;
365 }
366 }
367 }
368
369
370 dev_lookup = dt_opencl_copy_host_to_device_constant(devid, lookup_size, lookup);
371 if(IS_NULL_PTR(dev_lookup)) goto error;
372
373 dev_code = dt_opencl_copy_host_to_device_constant(devid, sizeof(code), code);
374 if(IS_NULL_PTR(dev_code)) goto error;
375
376 dev_ips = dt_opencl_copy_host_to_device_constant(devid, ips_size, ips);
377 if(IS_NULL_PTR(dev_ips)) goto error;
378
379 // green equilibration for Bayer sensors
380 if(piece->dsc_in.filters != 9u && data->green_eq != DT_IOP_GREEN_EQ_NO)
381 {
382 dev_green_eq = dt_opencl_alloc_device(devid, roi_in->width, roi_in->height, sizeof(float));
383 if(IS_NULL_PTR(dev_green_eq)) goto error;
384
385 if(!green_equilibration_cl(self, pipe, piece, dev_in, dev_green_eq, roi_in))
386 goto error;
387
388 dev_in = dev_green_eq;
389 }
390
391 int width = roi_out->width;
392 int height = roi_out->height;
393
394 dev_aux = dev_out;
395
396 dev_tmp = dt_opencl_alloc_device(devid, roi_in->width, roi_in->height, sizeof(float) * 4);
397 if(IS_NULL_PTR(dev_tmp)) goto error;
398
399 {
400 // manage borders for linear interpolation part
401 const int border = 1;
402
403 size_t sizes[3] = { ROUNDUPDWD(width, devid), ROUNDUPDHT(height, devid), 1 };
404 dt_opencl_set_kernel_arg(devid, gd->kernel_vng_border_interpolate, 0, sizeof(cl_mem), (void *)&dev_in);
405 dt_opencl_set_kernel_arg(devid, gd->kernel_vng_border_interpolate, 1, sizeof(cl_mem), (void *)&dev_tmp);
406 dt_opencl_set_kernel_arg(devid, gd->kernel_vng_border_interpolate, 2, sizeof(int), (void *)&width);
407 dt_opencl_set_kernel_arg(devid, gd->kernel_vng_border_interpolate, 3, sizeof(int), (void *)&height);
408 dt_opencl_set_kernel_arg(devid, gd->kernel_vng_border_interpolate, 4, sizeof(int), (void *)&border);
409 dt_opencl_set_kernel_arg(devid, gd->kernel_vng_border_interpolate, 5, sizeof(int), (void *)&roi_in->x);
410 dt_opencl_set_kernel_arg(devid, gd->kernel_vng_border_interpolate, 6, sizeof(int), (void *)&roi_in->y);
411 dt_opencl_set_kernel_arg(devid, gd->kernel_vng_border_interpolate, 7, sizeof(uint32_t), (void *)&filters4);
412 dt_opencl_set_kernel_arg(devid, gd->kernel_vng_border_interpolate, 8, sizeof(cl_mem), (void *)&dev_xtrans);
414 if(err != CL_SUCCESS) goto error;
415 }
416
417 {
418 // do linear interpolation
420 = (dt_opencl_local_buffer_t){ .xoffset = 2*1, .xfactor = 1, .yoffset = 2*1, .yfactor = 1,
421 .cellsize = 1 * sizeof(float), .overhead = 0,
422 .sizex = 1 << 8, .sizey = 1 << 8 };
423
425 goto error;
426
427 size_t sizes[3] = { ROUNDUP(width, locopt.sizex), ROUNDUP(height, locopt.sizey), 1 };
428 size_t local[3] = { locopt.sizex, locopt.sizey, 1 };
429 dt_opencl_set_kernel_arg(devid, gd->kernel_vng_lin_interpolate, 0, sizeof(cl_mem), (void *)&dev_in);
430 dt_opencl_set_kernel_arg(devid, gd->kernel_vng_lin_interpolate, 1, sizeof(cl_mem), (void *)&dev_tmp);
431 dt_opencl_set_kernel_arg(devid, gd->kernel_vng_lin_interpolate, 2, sizeof(int), (void *)&width);
432 dt_opencl_set_kernel_arg(devid, gd->kernel_vng_lin_interpolate, 3, sizeof(int), (void *)&height);
433 dt_opencl_set_kernel_arg(devid, gd->kernel_vng_lin_interpolate, 4, sizeof(uint32_t), (void *)&filters4);
434 dt_opencl_set_kernel_arg(devid, gd->kernel_vng_lin_interpolate, 5, sizeof(cl_mem), (void *)&dev_lookup);
436 sizeof(float) * (locopt.sizex + 2) * (locopt.sizey + 2), NULL);
438 if(err != CL_SUCCESS) goto error;
439 }
440
441 {
442 // do full VNG interpolation
444 = (dt_opencl_local_buffer_t){ .xoffset = 2*2, .xfactor = 1, .yoffset = 2*2, .yfactor = 1,
445 .cellsize = 4 * sizeof(float), .overhead = 0,
446 .sizex = 1 << 8, .sizey = 1 << 8 };
447
448 if(!dt_opencl_local_buffer_opt(devid, gd->kernel_vng_interpolate, &locopt))
449 goto error;
450
451 size_t sizes[3] = { ROUNDUP(width, locopt.sizex), ROUNDUP(height, locopt.sizey), 1 };
452 size_t local[3] = { locopt.sizex, locopt.sizey, 1 };
453 dt_opencl_set_kernel_arg(devid, gd->kernel_vng_interpolate, 0, sizeof(cl_mem), (void *)&dev_tmp);
454 dt_opencl_set_kernel_arg(devid, gd->kernel_vng_interpolate, 1, sizeof(cl_mem), (void *)&dev_aux);
455 dt_opencl_set_kernel_arg(devid, gd->kernel_vng_interpolate, 2, sizeof(int), (void *)&width);
456 dt_opencl_set_kernel_arg(devid, gd->kernel_vng_interpolate, 3, sizeof(int), (void *)&height);
457 dt_opencl_set_kernel_arg(devid, gd->kernel_vng_interpolate, 4, sizeof(int), (void *)&roi_in->x);
458 dt_opencl_set_kernel_arg(devid, gd->kernel_vng_interpolate, 5, sizeof(int), (void *)&roi_in->y);
459 dt_opencl_set_kernel_arg(devid, gd->kernel_vng_interpolate, 6, sizeof(uint32_t), (void *)&filters4);
460 dt_opencl_set_kernel_arg(devid, gd->kernel_vng_interpolate, 7, 4*sizeof(float), (void *)processed_maximum);
461 dt_opencl_set_kernel_arg(devid, gd->kernel_vng_interpolate, 8, sizeof(cl_mem), (void *)&dev_xtrans);
462 dt_opencl_set_kernel_arg(devid, gd->kernel_vng_interpolate, 9, sizeof(cl_mem), (void *)&dev_ips);
463 dt_opencl_set_kernel_arg(devid, gd->kernel_vng_interpolate, 10, sizeof(cl_mem), (void *)&dev_code);
464 dt_opencl_set_kernel_arg(devid, gd->kernel_vng_interpolate, 11, sizeof(float) * 4 * (locopt.sizex + 4) * (locopt.sizey + 4), NULL);
466 if(err != CL_SUCCESS) goto error;
467 }
468
469 {
470 // manage borders
471 const int border = 2;
472
473 size_t sizes[3] = { ROUNDUPDWD(width, devid), ROUNDUPDHT(height, devid), 1 };
474 dt_opencl_set_kernel_arg(devid, gd->kernel_vng_border_interpolate, 0, sizeof(cl_mem), (void *)&dev_in);
475 dt_opencl_set_kernel_arg(devid, gd->kernel_vng_border_interpolate, 1, sizeof(cl_mem), (void *)&dev_aux);
476 dt_opencl_set_kernel_arg(devid, gd->kernel_vng_border_interpolate, 2, sizeof(int), (void *)&width);
477 dt_opencl_set_kernel_arg(devid, gd->kernel_vng_border_interpolate, 3, sizeof(int), (void *)&height);
478 dt_opencl_set_kernel_arg(devid, gd->kernel_vng_border_interpolate, 4, sizeof(int), (void *)&border);
479 dt_opencl_set_kernel_arg(devid, gd->kernel_vng_border_interpolate, 5, sizeof(int), (void *)&roi_in->x);
480 dt_opencl_set_kernel_arg(devid, gd->kernel_vng_border_interpolate, 6, sizeof(int), (void *)&roi_in->y);
481 dt_opencl_set_kernel_arg(devid, gd->kernel_vng_border_interpolate, 7, sizeof(uint32_t), (void *)&filters4);
482 dt_opencl_set_kernel_arg(devid, gd->kernel_vng_border_interpolate, 8, sizeof(cl_mem), (void *)&dev_xtrans);
484 if(err != CL_SUCCESS) goto error;
485 }
486
487 if(filters4 != 9)
488 {
489 // for Bayer sensors mix the two green channels
490 size_t origin[] = { 0, 0, 0 };
491 size_t region[] = { width, height, 1 };
492 err = dt_opencl_enqueue_copy_image(devid, dev_aux, dev_tmp, origin, origin, region);
493 if(err != CL_SUCCESS) goto error;
494
495 size_t sizes[3] = { ROUNDUPDWD(width, devid), ROUNDUPDHT(height, devid), 1 };
496 dt_opencl_set_kernel_arg(devid, gd->kernel_vng_green_equilibrate, 0, sizeof(cl_mem), (void *)&dev_tmp);
497 dt_opencl_set_kernel_arg(devid, gd->kernel_vng_green_equilibrate, 1, sizeof(cl_mem), (void *)&dev_aux);
498 dt_opencl_set_kernel_arg(devid, gd->kernel_vng_green_equilibrate, 2, sizeof(int), (void *)&width);
499 dt_opencl_set_kernel_arg(devid, gd->kernel_vng_green_equilibrate, 3, sizeof(int), (void *)&height);
501 if(err != CL_SUCCESS) goto error;
502 }
503 if(dev_aux != dev_out) dt_opencl_release_mem_object(dev_aux);
504 dev_aux = NULL;
505
507 dev_tmp = NULL;
508
510 dev_xtrans = NULL;
511
513 dev_lookup = NULL;
514
516
518 dev_code = NULL;
519
521 dev_ips = NULL;
522
523 dt_opencl_release_mem_object(dev_green_eq);
524 dev_green_eq = NULL;
525
526 dt_free(ips);
527
528 // color smoothing
529 if((data->color_smoothing) && smooth)
530 {
531 if(!color_smoothing_cl(self, pipe, piece, dev_out, dev_out, roi_out, data->color_smoothing))
532 goto error;
533 }
534
535 return TRUE;
536
537error:
538 if(dev_aux != dev_out) dt_opencl_release_mem_object(dev_aux);
545 dt_opencl_release_mem_object(dev_green_eq);
546 dt_free(ips);
547 dt_print(DT_DEBUG_OPENCL, "[opencl_demosaic] couldn't enqueue kernel! %d\n", err);
548 return FALSE;
549}
550#endif // HAVE_OPENCL
551
552// clang-format off
553// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
554// vim: shiftwidth=2 expandtab tabstop=2 cindent
555// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
556// 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
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 lin_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])
Definition basic.c:22
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
int width
Definition bilateral.h:1
int height
Definition bilateral.h:1
static float lookup(read_only image2d_t lut, const float x)
Definition color_conversion.h:84
const float i
Definition colorspaces_inline_conversions.h:440
const float g
Definition colorspaces_inline_conversions.h:674
const dt_aligned_pixel_t f
Definition colorspaces_inline_conversions.h:102
const dt_colormatrix_t dt_aligned_pixel_t out
Definition colorspaces_inline_conversions.h:42
static const int row
Definition colorspaces_inline_conversions.h:35
void dt_print(dt_debug_thread_t thread, const char *msg,...)
Definition darktable.c:1448
@ DT_DEBUG_OPENCL
Definition darktable.h:721
#define dt_pixelpipe_cache_alloc_align_cache(size, id)
Definition darktable.h:433
#define dt_free(ptr)
Definition darktable.h:456
#define dt_pixelpipe_cache_free_align(mem)
Definition darktable.h:453
#define __DT_CLONE_TARGETS__
Definition darktable.h:367
#define __OMP_PARALLEL_FOR__(...)
Definition darktable.h:258
#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
@ DT_IOP_GREEN_EQ_NO
Definition demosaic.c:135
static void weight(const float *c1, const float *c2, const float sharpen, dt_aligned_pixel_t weight)
Definition eaw.c:30
const dt_collection_filter_flag_t colors[6]
Definition filter.c:295
#define FILTERS_ARE_4BAYER(filters)
Definition imageio.h:55
static int fcol(const int row, const int col, const uint32_t filters, const uint8_t(*const xtrans)[6])
Definition imageop_math.h:222
static const float x
Definition iop_profile.h:235
const int t
Definition iop_profile.h:225
size_t size
Definition mipmap_cache.c:3
float dt_aligned_pixel_t[4]
Definition noiseprofile.c:28
int dt_opencl_local_buffer_opt(const int devid, const int kernel, dt_opencl_local_buffer_t *factors)
Definition opencl.c:2970
int dt_opencl_enqueue_kernel_2d(const int dev, const int kernel, const size_t *sizes)
Definition opencl.c:1951
void * dt_opencl_alloc_device(const int devid, const int width, const int height, const int bpp)
Definition opencl.c:2286
void * dt_opencl_copy_host_to_device_constant(const int devid, const size_t size, void *host)
Definition opencl.c:2147
int dt_opencl_enqueue_copy_image(const int devid, cl_mem src, cl_mem dst, size_t *orig_src, size_t *orig_dst, size_t *region)
Definition opencl.c:2076
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:1942
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:1957
void dt_opencl_release_mem_object(cl_mem mem)
Definition opencl.c:2198
#define ROUNDUP(a, n)
Definition opencl.h:78
#define ROUNDUPDHT(a, b)
Definition opencl.h:82
#define ROUNDUPDWD(a, b)
Definition opencl.h:81
Definition pixelpipe_hb.h:96
dt_iop_buffer_dsc_t dsc_in
Definition pixelpipe_hb.h:142
struct dt_iop_module_t *void * data
Definition pixelpipe_hb.h:97
Definition pixelpipe_hb.h:218
int devid
Definition pixelpipe_hb.h:308
uint32_t filters
Definition format.h:60
uint8_t xtrans[6][6]
Definition format.h:70
dt_aligned_pixel_t processed_maximum
Definition format.h:85
Definition demosaic.c:228
uint32_t green_eq
Definition demosaic.c:229
uint32_t color_smoothing
Definition demosaic.c:230
Definition demosaic.c:162
int kernel_vng_interpolate
Definition demosaic.c:191
int kernel_vng_green_equilibrate
Definition demosaic.c:190
int kernel_vng_border_interpolate
Definition demosaic.c:178
int kernel_vng_lin_interpolate
Definition demosaic.c:179
Definition imageop.h:246
dt_iop_global_data_t * global_data
Definition imageop.h:316
Region of interest passed through the pixelpipe.
Definition imageop.h:72
int x
Definition imageop.h:73
int width
Definition imageop.h:73
int height
Definition imageop.h:73
int y
Definition imageop.h:73
Definition opencl.h:269
const int xoffset
Definition opencl.h:270
int sizey
Definition opencl.h:277
int sizex
Definition opencl.h:276
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