Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
gaussian.c
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2012, 2014, 2016-2017 Ulrich Pegelow.
4 Copyright (C) 2013-2016 Tobias Ellinghaus.
5 Copyright (C) 2014, 2016 Roman Lebedev.
6 Copyright (C) 2016 johannes hanika.
7 Copyright (C) 2019 Andreas Schneider.
8 Copyright (C) 2019, 2025-2026 Aurélien PIERRE.
9 Copyright (C) 2020-2021 Hubert Kowalski.
10 Copyright (C) 2020 Pascal Obry.
11 Copyright (C) 2020-2021 Ralf Brown.
12 Copyright (C) 2022 Hanno Schwalm.
13 Copyright (C) 2022 Martin Bařinka.
14
15 darktable is free software: you can redistribute it and/or modify
16 it under the terms of the GNU General Public License as published by
17 the Free Software Foundation, either version 3 of the License, or
18 (at your option) any later version.
19
20 darktable is distributed in the hope that it will be useful,
21 but WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 GNU General Public License for more details.
24
25 You should have received a copy of the GNU General Public License
26 along with darktable. If not, see <http://www.gnu.org/licenses/>.
27*/
28
29
30#include "system/macros.h"
31#include "system/openmp.h"
33#include "system/mem_alloc.h"
34#include "system/simd.h"
36#include <assert.h>
37#include <math.h>
38#include "pixel/gaussian.h"
39#include "math/math.h"
40#include "common/opencl.h"
41
42#define BLOCKSIZE (1 << 6)
43
44static inline __attribute__((always_inline)) void compute_gauss_params(const float sigma, dt_gaussian_order_t order, float *a0, float *a1,
45 float *a2, float *a3, float *b1, float *b2, float *coefp, float *coefn)
46{
47 const float alpha = 1.695f / sigma;
48 const float ema = expf(-alpha);
49 const float ema2 = expf(-2.0f * alpha);
50 *b1 = -2.0f * ema;
51 *b2 = ema2;
52 *a0 = 0.0f;
53 *a1 = 0.0f;
54 *a2 = 0.0f;
55 *a3 = 0.0f;
56 *coefp = 0.0f;
57 *coefn = 0.0f;
58
59 switch(order)
60 {
61 default:
63 {
64 const float k = (1.0f - ema) * (1.0f - ema) / (1.0f + (2.0f * alpha * ema) - ema2);
65 *a0 = k;
66 *a1 = k * (alpha - 1.0f) * ema;
67 *a2 = k * (alpha + 1.0f) * ema;
68 *a3 = -k * ema2;
69 }
70 break;
71
73 {
74 *a0 = (1.0f - ema) * (1.0f - ema);
75 *a1 = 0.0f;
76 *a2 = -*a0;
77 *a3 = 0.0f;
78 }
79 break;
80
82 {
83 const float k = -(ema2 - 1.0f) / (2.0f * alpha * ema);
84 float kn = -2.0f * (-1.0f + (3.0f * ema) - (3.0f * ema * ema) + (ema * ema * ema));
85 kn /= ((3.0f * ema) + 1.0f + (3.0f * ema * ema) + (ema * ema * ema));
86 *a0 = kn;
87 *a1 = -kn * (1.0f + (k * alpha)) * ema;
88 *a2 = kn * (1.0f - (k * alpha)) * ema;
89 *a3 = -kn * ema2;
90 }
91 }
92
93 *coefp = (*a0 + *a1) / (1.0f + *b1 + *b2);
94 *coefn = (*a2 + *a3) / (1.0f + *b1 + *b2);
95}
96
97size_t dt_gaussian_memory_use(const int width, // width of input image
98 const int height, // height of input image
99 const int channels) // channels per pixel
100{
101 return sizeof(float) * channels * width * height;
102}
103
104#ifdef HAVE_OPENCL
105size_t dt_gaussian_memory_use_cl(const int width, // width of input image
106 const int height, // height of input image
107 const int channels) // channels per pixel
108{
109 return sizeof(float) * channels * (width + BLOCKSIZE) * (height + BLOCKSIZE) * 2;
110}
111#endif /* HAVE_OPENCL */
112
113size_t dt_gaussian_singlebuffer_size(const int width, // width of input image
114 const int height, // height of input image
115 const int channels) // channels per pixel
116{
117 size_t mem_use;
118#ifdef HAVE_OPENCL
119 mem_use = sizeof(float) * channels * (width + BLOCKSIZE) * (height + BLOCKSIZE);
120#else
121 mem_use = sizeof(float) * channels * width * height;
122#endif
123 return mem_use;
124}
125
126
127dt_gaussian_t *dt_gaussian_init(const int width, // width of input image
128 const int height, // height of input image
129 const int channels, // channels per pixel
130 const float *max, // maximum allowed values per channel for clamping
131 const float *min, // minimum allowed values per channel for clamping
132 const float sigma, // gaussian sigma
133 const int order) // order of gaussian blur
134{
135 dt_gaussian_t *g = (dt_gaussian_t *)malloc(sizeof(dt_gaussian_t));
136 if(IS_NULL_PTR(g)) return NULL;
137
138 g->width = width;
139 g->height = height;
140 g->channels = channels;
141 g->sigma = sigma;
142 g->order = order;
143 g->buf = NULL;
144 g->max = (float *)calloc(channels, sizeof(float));
145 g->min = (float *)calloc(channels, sizeof(float));
146
147 if(IS_NULL_PTR(g->min) || IS_NULL_PTR(g->max)) goto error;
148
149 for(int k = 0; k < channels; k++)
150 {
151 g->max[k] = max[k];
152 g->min[k] = min[k];
153 }
154
155 g->buf = dt_pixelpipe_cache_alloc_align_float_cache((size_t)channels * width * height, 0);
156 if(IS_NULL_PTR(g->buf)) goto error;
157
158 return g;
159
160error:
162 if(g->max)
163 {
164 dt_free(g->max);
165 }
166 if(g->min)
167 {
168 dt_free(g->min);
169 }
170 dt_free(g);
171 return NULL;
172}
173
174
176void dt_gaussian_blur(dt_gaussian_t *g, const float *const in, float *const out)
177{
178
179 const int width = g->width;
180 const int height = g->height;
181 const int ch = MIN(4, g->channels); // just to appease zealous compiler warnings about stack usage
182
183 float a0, a1, a2, a3, b1, b2, coefp, coefn;
184
185 compute_gauss_params(g->sigma, g->order, &a0, &a1, &a2, &a3, &b1, &b2, &coefp, &coefn);
186
187 float *temp = g->buf;
188
189 float *Labmax = g->max;
190 float *Labmin = g->min;
191
192// vertical blur column by column
194 for(int i = 0; i < width; i++)
195 {
196 dt_aligned_pixel_t xp = {0.0f};
197 dt_aligned_pixel_t yb = {0.0f};
198 dt_aligned_pixel_t yp = {0.0f};
199
200 // forward filter
201 for(int k = 0; k < ch; k++)
202 {
203 xp[k] = CLAMPF(in[(size_t)i * ch + k], Labmin[k], Labmax[k]);
204 yb[k] = xp[k] * coefp;
205 yp[k] = yb[k];
206 }
207
208 dt_aligned_pixel_t xc = {0.0f};
209 dt_aligned_pixel_t yc = {0.0f};
210 dt_aligned_pixel_t xn = {0.0f};
211 dt_aligned_pixel_t xa = {0.0f};
212 dt_aligned_pixel_t yn = {0.0f};
213 dt_aligned_pixel_t ya = {0.0f};
214 for(int j = 0; j < height; j++)
215 {
216 size_t offset = ((size_t)j * width + i) * ch;
217
218 for(int k = 0; k < ch; k++)
219 {
220 xc[k] = CLAMPF(in[offset + k], Labmin[k], Labmax[k]);
221 yc[k] = (a0 * xc[k]) + (a1 * xp[k]) - (b1 * yp[k]) - (b2 * yb[k]);
222
223 temp[offset + k] = yc[k];
224
225 xp[k] = xc[k];
226 yb[k] = yp[k];
227 yp[k] = yc[k];
228 }
229 }
230
231 // backward filter
232 for(int k = 0; k < ch; k++)
233 {
234 xn[k] = CLAMPF(in[((size_t)(height - 1) * width + i) * ch + k], Labmin[k], Labmax[k]);
235 xa[k] = xn[k];
236 yn[k] = xn[k] * coefn;
237 ya[k] = yn[k];
238 }
239
240 for(int j = height - 1; j > -1; j--)
241 {
242 size_t offset = ((size_t)j * width + i) * ch;
243
244 for(int k = 0; k < ch; k++)
245 {
246 xc[k] = CLAMPF(in[offset + k], Labmin[k], Labmax[k]);
247
248 yc[k] = (a2 * xn[k]) + (a3 * xa[k]) - (b1 * yn[k]) - (b2 * ya[k]);
249
250 xa[k] = xn[k];
251 xn[k] = xc[k];
252 ya[k] = yn[k];
253 yn[k] = yc[k];
254
255 temp[offset + k] += yc[k];
256 }
257 }
258 }
259
260// horizontal blur line by line
262 for(int j = 0; j < height; j++)
263 {
264 dt_aligned_pixel_t xp = {0.0f};
265 dt_aligned_pixel_t yb = {0.0f};
266 dt_aligned_pixel_t yp = {0.0f};
267
268 // forward filter
269 for(int k = 0; k < ch; k++)
270 {
271 xp[k] = CLAMPF(temp[(size_t)j * width * ch + k], Labmin[k], Labmax[k]);
272 yb[k] = xp[k] * coefp;
273 yp[k] = yb[k];
274 }
275
276 dt_aligned_pixel_t xc = {0.0f};
277 dt_aligned_pixel_t yc = {0.0f};
278 dt_aligned_pixel_t xn = {0.0f};
279 dt_aligned_pixel_t xa = {0.0f};
280 dt_aligned_pixel_t yn = {0.0f};
281 dt_aligned_pixel_t ya = {0.0f};
282
283 for(int i = 0; i < width; i++)
284 {
285 size_t offset = ((size_t)j * width + i) * ch;
286
287 for(int k = 0; k < ch; k++)
288 {
289 xc[k] = CLAMPF(temp[offset + k], Labmin[k], Labmax[k]);
290 yc[k] = (a0 * xc[k]) + (a1 * xp[k]) - (b1 * yp[k]) - (b2 * yb[k]);
291
292 out[offset + k] = yc[k];
293
294 xp[k] = xc[k];
295 yb[k] = yp[k];
296 yp[k] = yc[k];
297 }
298 }
299
300 // backward filter
301 for(int k = 0; k < ch; k++)
302 {
303 xn[k] = CLAMPF(temp[((size_t)(j + 1) * width - 1) * ch + k], Labmin[k], Labmax[k]);
304 xa[k] = xn[k];
305 yn[k] = xn[k] * coefn;
306 ya[k] = yn[k];
307 }
308
309 for(int i = width - 1; i > -1; i--)
310 {
311 size_t offset = ((size_t)j * width + i) * ch;
312
313 for(int k = 0; k < ch; k++)
314 {
315 xc[k] = CLAMPF(temp[offset + k], Labmin[k], Labmax[k]);
316
317 yc[k] = (a2 * xn[k]) + (a3 * xa[k]) - (b1 * yn[k]) - (b2 * ya[k]);
318
319 xa[k] = xn[k];
320 xn[k] = xc[k];
321 ya[k] = yn[k];
322 yn[k] = yc[k];
323
324 out[offset + k] += yc[k];
325 }
326 }
327 }
328}
329
330void dt_gaussian_blur_4c(dt_gaussian_t *g, const float *const in, float *const out)
331{
332 return dt_gaussian_blur(g, in, out);
333}
334
336{
337 if(IS_NULL_PTR(g)) return;
339 dt_free(g->min);
340 dt_free(g->max);
341 dt_free(g);
342}
343
344
345#ifdef HAVE_OPENCL
346/* The kernels this subsystem compiles, owned HERE. They used to be handed to
347 * common/opencl.c, parked on the application-wide dt_opencl_t, and read back from it --
348 * a round trip through a god-struct that added nothing but an ordering. opencl.c still
349 * calls init/free, because the kernels must be built after the devices exist, but the
350 * pointer never leaves this file. */
352
354{
356
357 const int program = 6; // gaussian.cl, from programs.conf
358 g->kernel_gaussian_column_1c = dt_opencl_create_kernel(program, "gaussian_column_1c");
359 g->kernel_gaussian_transpose_1c = dt_opencl_create_kernel(program, "gaussian_transpose_1c");
360 g->kernel_gaussian_column_4c = dt_opencl_create_kernel(program, "gaussian_column_4c");
361 g->kernel_gaussian_transpose_4c = dt_opencl_create_kernel(program, "gaussian_transpose_4c");
363}
364
366{
367 if(IS_NULL_PTR(g)) return;
368 dt_free(g->min);
369 dt_free(g->max);
370 // free device mem
373 dt_free(g);
374}
375
377 const int width, // width of input image
378 const int height, // height of input image
379 const int channels, // channels per pixel
380 const float *max, // maximum allowed values per channel for clamping
381 const float *min, // minimum allowed values per channel for clamping
382 const float sigma, // gaussian sigma
383 const int order) // order of gaussian blur
384{
385 assert(channels == 1 || channels == 4);
386
387 if(!(channels == 1 || channels == 4)) return NULL;
388
390 if(IS_NULL_PTR(g)) return NULL;
391
393 g->devid = devid;
394 g->width = width;
395 g->height = height;
396 g->channels = channels;
397 g->sigma = sigma;
398 g->order = order;
399 g->dev_temp1 = NULL;
400 g->dev_temp2 = NULL;
401 g->max = (float *)calloc(channels, sizeof(float));
402 g->min = (float *)calloc(channels, sizeof(float));
403
404 if(IS_NULL_PTR(g->min) || IS_NULL_PTR(g->max)) goto error;
405
406 for(int k = 0; k < channels; k++)
407 {
408 g->max[k] = max[k];
409 g->min[k] = min[k];
410 }
411
412 int kernel_gaussian_transpose = (channels == 1) ? g->global->kernel_gaussian_transpose_1c
413 : g->global->kernel_gaussian_transpose_4c;
414 int blocksize;
415
417 = (dt_opencl_local_buffer_t){ .xoffset = 1, .xfactor = 1, .yoffset = 0, .yfactor = 1,
418 .cellsize = channels * sizeof(float), .overhead = 0,
419 .sizex = BLOCKSIZE, .sizey = BLOCKSIZE };
420
421 if(dt_opencl_local_buffer_opt(devid, kernel_gaussian_transpose, &locopt))
422 blocksize = MIN(locopt.sizex, locopt.sizey);
423 else
424 blocksize = 1;
425
426 // width and height of intermediate buffers. Need to be multiples of blocksize
427 const size_t bwidth = ROUNDUP(width, blocksize);
428 const size_t bheight = ROUNDUP(height, blocksize);
429
430 g->blocksize = blocksize;
431 g->bwidth = bwidth;
432 g->bheight = bheight;
433
434 // get intermediate vector buffers with read-write access
435 g->dev_temp1 = dt_opencl_alloc_device_buffer(devid, sizeof(float) * channels * bwidth * bheight);
436 if(IS_NULL_PTR(g->dev_temp1)) goto error;
437 g->dev_temp2 = dt_opencl_alloc_device_buffer(devid, sizeof(float) * channels * bwidth * bheight);
438 if(IS_NULL_PTR(g->dev_temp2)) goto error;
439
440 return g;
441
442error:
443 dt_free(g->min);
444 dt_free(g->max);
447 g->dev_temp1 = g->dev_temp2 = NULL;
448 dt_free(g);
449 return NULL;
450}
451
452
453cl_int dt_gaussian_blur_cl(dt_gaussian_cl_t *g, cl_mem dev_in, cl_mem dev_out)
454{
455 cl_int err = -999;
456 const int devid = g->devid;
457
458 const int width = g->width;
459 const int height = g->height;
460 const int channels = g->channels;
461 const size_t bpp = sizeof(float) * channels;
462 cl_mem dev_temp1 = g->dev_temp1;
463 cl_mem dev_temp2 = g->dev_temp2;
464
465 const int blocksize = g->blocksize;
466 const int bwidth = g->bwidth;
467 const int bheight = g->bheight;
468
469 dt_aligned_pixel_t Labmax = { 0.0f };
470 dt_aligned_pixel_t Labmin = { 0.0f };
471
472 for(int k = 0; k < MIN(channels, 4); k++)
473 {
474 Labmax[k] = g->max[k];
475 Labmin[k] = g->min[k];
476 }
477
478 int kernel_gaussian_column = -1;
479 int kernel_gaussian_transpose = -1;
480
481 if(channels == 1)
482 {
483 kernel_gaussian_column = g->global->kernel_gaussian_column_1c;
484 kernel_gaussian_transpose = g->global->kernel_gaussian_transpose_1c;
485 }
486 else if(channels == 4)
487 {
488 kernel_gaussian_column = g->global->kernel_gaussian_column_4c;
489 kernel_gaussian_transpose = g->global->kernel_gaussian_transpose_4c;
490 }
491 else
492 return err;
493
494 size_t origin[] = { 0, 0, 0 };
495 size_t region[] = { width, height, 1 };
496 size_t local[] = { blocksize, blocksize, 1 };
497 size_t sizes[3];
498
499 // compute gaussian parameters
500 float a0, a1, a2, a3, b1, b2, coefp, coefn;
501 compute_gauss_params(g->sigma, g->order, &a0, &a1, &a2, &a3, &b1, &b2, &coefp, &coefn);
502
503 // copy dev_in to intermediate buffer dev_temp1
504 err = dt_opencl_enqueue_copy_image_to_buffer(devid, dev_in, dev_temp1, origin, region, 0);
505 if(err != CL_SUCCESS) return err;
506
507 // first blur step: column by column with dev_temp1 -> dev_temp2
508 sizes[0] = ROUNDUPDWD(width, devid);
509 sizes[1] = 1;
510 sizes[2] = 1;
511 dt_opencl_set_kernel_arg(devid, kernel_gaussian_column, 0, sizeof(cl_mem), (void *)&dev_temp1);
512 dt_opencl_set_kernel_arg(devid, kernel_gaussian_column, 1, sizeof(cl_mem), (void *)&dev_temp2);
513 dt_opencl_set_kernel_arg(devid, kernel_gaussian_column, 2, sizeof(int), (void *)&width);
514 dt_opencl_set_kernel_arg(devid, kernel_gaussian_column, 3, sizeof(int), (void *)&height);
515 dt_opencl_set_kernel_arg(devid, kernel_gaussian_column, 4, sizeof(float), (void *)&a0);
516 dt_opencl_set_kernel_arg(devid, kernel_gaussian_column, 5, sizeof(float), (void *)&a1);
517 dt_opencl_set_kernel_arg(devid, kernel_gaussian_column, 6, sizeof(float), (void *)&a2);
518 dt_opencl_set_kernel_arg(devid, kernel_gaussian_column, 7, sizeof(float), (void *)&a3);
519 dt_opencl_set_kernel_arg(devid, kernel_gaussian_column, 8, sizeof(float), (void *)&b1);
520 dt_opencl_set_kernel_arg(devid, kernel_gaussian_column, 9, sizeof(float), (void *)&b2);
521 dt_opencl_set_kernel_arg(devid, kernel_gaussian_column, 10, sizeof(float), (void *)&coefp);
522 dt_opencl_set_kernel_arg(devid, kernel_gaussian_column, 11, sizeof(float), (void *)&coefn);
523 dt_opencl_set_kernel_arg(devid, kernel_gaussian_column, 12, sizeof(float) * channels, (void *)&Labmax);
524 dt_opencl_set_kernel_arg(devid, kernel_gaussian_column, 13, sizeof(float) * channels, (void *)&Labmin);
525 err = dt_opencl_enqueue_kernel_2d(devid, kernel_gaussian_column, sizes);
526 if(err != CL_SUCCESS) return err;
527
528 // intermediate step: transpose dev_temp2 -> dev_temp1
529 sizes[0] = bwidth;
530 sizes[1] = bheight;
531 sizes[2] = 1;
532 dt_opencl_set_kernel_arg(devid, kernel_gaussian_transpose, 0, sizeof(cl_mem), (void *)&dev_temp2);
533 dt_opencl_set_kernel_arg(devid, kernel_gaussian_transpose, 1, sizeof(cl_mem), (void *)&dev_temp1);
534 dt_opencl_set_kernel_arg(devid, kernel_gaussian_transpose, 2, sizeof(int), (void *)&width);
535 dt_opencl_set_kernel_arg(devid, kernel_gaussian_transpose, 3, sizeof(int), (void *)&height);
536 dt_opencl_set_kernel_arg(devid, kernel_gaussian_transpose, 4, sizeof(int), (void *)&blocksize);
537 dt_opencl_set_kernel_arg(devid, kernel_gaussian_transpose, 5, bpp * blocksize * (blocksize + 1), NULL);
538 err = dt_opencl_enqueue_kernel_2d_with_local(devid, kernel_gaussian_transpose, sizes, local);
539 if(err != CL_SUCCESS) return err;
540
541
542 // second blur step: column by column of transposed image with dev_temp1 -> dev_temp2 (!! height <-> width
543 // !!)
544 sizes[0] = ROUNDUPDHT(height, devid);
545 sizes[1] = 1;
546 sizes[2] = 1;
547 dt_opencl_set_kernel_arg(devid, kernel_gaussian_column, 0, sizeof(cl_mem), (void *)&dev_temp1);
548 dt_opencl_set_kernel_arg(devid, kernel_gaussian_column, 1, sizeof(cl_mem), (void *)&dev_temp2);
549 dt_opencl_set_kernel_arg(devid, kernel_gaussian_column, 2, sizeof(int), (void *)&height);
550 dt_opencl_set_kernel_arg(devid, kernel_gaussian_column, 3, sizeof(int), (void *)&width);
551 dt_opencl_set_kernel_arg(devid, kernel_gaussian_column, 4, sizeof(float), (void *)&a0);
552 dt_opencl_set_kernel_arg(devid, kernel_gaussian_column, 5, sizeof(float), (void *)&a1);
553 dt_opencl_set_kernel_arg(devid, kernel_gaussian_column, 6, sizeof(float), (void *)&a2);
554 dt_opencl_set_kernel_arg(devid, kernel_gaussian_column, 7, sizeof(float), (void *)&a3);
555 dt_opencl_set_kernel_arg(devid, kernel_gaussian_column, 8, sizeof(float), (void *)&b1);
556 dt_opencl_set_kernel_arg(devid, kernel_gaussian_column, 9, sizeof(float), (void *)&b2);
557 dt_opencl_set_kernel_arg(devid, kernel_gaussian_column, 10, sizeof(float), (void *)&coefp);
558 dt_opencl_set_kernel_arg(devid, kernel_gaussian_column, 11, sizeof(float), (void *)&coefn);
559 dt_opencl_set_kernel_arg(devid, kernel_gaussian_column, 12, sizeof(float) * channels, (void *)&Labmax);
560 dt_opencl_set_kernel_arg(devid, kernel_gaussian_column, 13, sizeof(float) * channels, (void *)&Labmin);
561 err = dt_opencl_enqueue_kernel_2d(devid, kernel_gaussian_column, sizes);
562 if(err != CL_SUCCESS) return err;
563
564
565 // transpose back dev_temp2 -> dev_temp1
566 sizes[0] = bheight;
567 sizes[1] = bwidth;
568 sizes[2] = 1;
569 dt_opencl_set_kernel_arg(devid, kernel_gaussian_transpose, 0, sizeof(cl_mem), (void *)&dev_temp2);
570 dt_opencl_set_kernel_arg(devid, kernel_gaussian_transpose, 1, sizeof(cl_mem), (void *)&dev_temp1);
571 dt_opencl_set_kernel_arg(devid, kernel_gaussian_transpose, 2, sizeof(int), (void *)&height);
572 dt_opencl_set_kernel_arg(devid, kernel_gaussian_transpose, 3, sizeof(int), (void *)&width);
573 dt_opencl_set_kernel_arg(devid, kernel_gaussian_transpose, 4, sizeof(int), (void *)&blocksize);
574 dt_opencl_set_kernel_arg(devid, kernel_gaussian_transpose, 5, bpp * blocksize * (blocksize + 1), NULL);
575 err = dt_opencl_enqueue_kernel_2d_with_local(devid, kernel_gaussian_transpose, sizes, local);
576 if(err != CL_SUCCESS) return err;
577
578 // finally produce output in dev_out
579 err = dt_opencl_enqueue_copy_buffer_to_image(devid, dev_temp1, dev_out, 0, origin, region);
580 if(err != CL_SUCCESS) return err;
581
582 return CL_SUCCESS;
583}
584
585
587{
589 _gaussian_cl_global = NULL;
590 if(IS_NULL_PTR(g)) return;
591 // destroy kernels
592 dt_opencl_free_kernel(g->kernel_gaussian_column_1c);
593 dt_opencl_free_kernel(g->kernel_gaussian_transpose_1c);
594 dt_opencl_free_kernel(g->kernel_gaussian_column_4c);
595 dt_opencl_free_kernel(g->kernel_gaussian_transpose_4c);
596 dt_free(g);
597}
598
599#endif
600// clang-format off
601// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
602// vim: shiftwidth=2 expandtab tabstop=2 cindent
603// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
604// clang-format on
static void error(char *msg)
Definition ashift_lsd.c:202
static const float const float const float min
const float max
const dt_colormatrix_t dt_aligned_pixel_t out
void dt_gaussian_free(dt_gaussian_t *g)
Definition gaussian.c:335
void dt_gaussian_free_cl(dt_gaussian_cl_t *g)
Definition gaussian.c:365
size_t dt_gaussian_memory_use_cl(const int width, const int height, const int channels)
Definition gaussian.c:105
void dt_gaussian_free_cl_global(void)
Definition gaussian.c:586
size_t dt_gaussian_singlebuffer_size(const int width, const int height, const int channels)
Definition gaussian.c:113
cl_int dt_gaussian_blur_cl(dt_gaussian_cl_t *g, cl_mem dev_in, cl_mem dev_out)
Definition gaussian.c:453
static dt_gaussian_cl_global_t * _gaussian_cl_global
Definition gaussian.c:351
__DT_CLONE_TARGETS__ void dt_gaussian_blur(dt_gaussian_t *g, const float *const in, float *const out)
Definition gaussian.c:176
void dt_gaussian_blur_4c(dt_gaussian_t *g, const float *const in, float *const out)
Definition gaussian.c:330
dt_gaussian_cl_t * dt_gaussian_init_cl(const int devid, const int width, const int height, const int channels, const float *max, const float *min, const float sigma, const int order)
Definition gaussian.c:376
dt_gaussian_t * dt_gaussian_init(const int width, const int height, const int channels, const float *max, const float *min, const float sigma, const int order)
Definition gaussian.c:127
size_t dt_gaussian_memory_use(const int width, const int height, const int channels)
Definition gaussian.c:97
void dt_gaussian_init_cl_global(void)
Definition gaussian.c:353
#define BLOCKSIZE
Definition gaussian.c:42
dt_gaussian_order_t
Definition gaussian.h:33
@ DT_IOP_GAUSSIAN_TWO
Definition gaussian.h:36
@ DT_IOP_GAUSSIAN_ONE
Definition gaussian.h:35
@ DT_IOP_GAUSSIAN_ZERO
Definition gaussian.h:34
int bpp
float *const restrict const size_t k
float *const restrict const size_t const size_t ch
#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
#define CLAMPF(a, mn, mx)
Definition math.h:91
#define dt_free(ptr)
g_free() ptr and set it to NULL, skipping both if it is already NULL.
Definition mem_alloc.h:171
uint32_t width
Definition mipmap_cache.c:0
uint32_t height
Definition mipmap_cache.c:1
int dt_opencl_local_buffer_opt(const int devid, const int kernel, dt_opencl_local_buffer_t *factors)
Definition opencl.c:3713
int dt_opencl_enqueue_kernel_2d(const int dev, const int kernel, const size_t *sizes)
Definition opencl.c:2554
void * dt_opencl_alloc_device_buffer(const int devid, const size_t size)
Definition opencl.c:2970
int dt_opencl_enqueue_copy_buffer_to_image(const int devid, cl_mem src_buffer, cl_mem dst_image, size_t offset, size_t *origin, size_t *region)
Definition opencl.c:2702
int dt_opencl_create_kernel(const int prog, const char *name)
Definition opencl.c:2448
void dt_opencl_free_kernel(const int kernel)
Definition opencl.c:2491
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:2545
int dt_opencl_enqueue_copy_image_to_buffer(const int devid, cl_mem src_image, cl_mem dst_buffer, size_t *origin, size_t *region, size_t offset)
Definition opencl.c:2690
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:2560
void dt_opencl_release_mem_object(cl_mem mem)
Definition opencl.c:2805
#define ROUNDUP(a, n)
Definition opencl.h:82
#define ROUNDUPDHT(a, b)
Definition opencl.h:86
#define ROUNDUPDWD(a, b)
Definition opencl.h:85
#define __OMP_PARALLEL_FOR__(...)
Definition openmp.h:95
#define dt_pixelpipe_cache_alloc_align_float_cache(pixels, id)
#define dt_pixelpipe_cache_free_align(mem)
DT_ALIGNED_PIXEL float dt_aligned_pixel_t[4]
Definition simd.h:53
float dt_aligned_pixel_simd_t __attribute__((vector_size(16), aligned(16)))
Apply one channel's tone curve to each of the three colour channels, or pass the channel through unto...
Definition simd.h:55
const float sigma
dt_gaussian_cl_global_t * global
Definition gaussian.h:77
#define __DT_CLONE_TARGETS__
#define MIN(a, b)
Definition thinplate.c:32