Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
sharpen.c
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2009-2013, 2016 johannes hanika.
4 Copyright (C) 2010-2011 Bruce Guenter.
5 Copyright (C) 2010-2011 Henrik Andersson.
6 Copyright (C) 2010 jan rinze.
7 Copyright (C) 2010-2011 Pascal de Bruijn.
8 Copyright (C) 2011 Antony Dovgal.
9 Copyright (C) 2011 Jérémy Rosen.
10 Copyright (C) 2011 Kanstantsin Shautsou.
11 Copyright (C) 2011 Olivier Tribout.
12 Copyright (C) 2011 Robert Bieber.
13 Copyright (C) 2011 Rostyslav Pidgornyi.
14 Copyright (C) 2011-2014, 2016, 2019 Tobias Ellinghaus.
15 Copyright (C) 2011-2012, 2014, 2016-2017 Ulrich Pegelow.
16 Copyright (C) 2012 Richard Wonka.
17 Copyright (C) 2013 Simon Spannagel.
18 Copyright (C) 2014, 2018, 2020, 2022 Pascal Obry.
19 Copyright (C) 2014-2016 Roman Lebedev.
20 Copyright (C) 2015 Edouard Gomez.
21 Copyright (C) 2015 Pedro Côrte-Real.
22 Copyright (C) 2017 Heiko Bauke.
23 Copyright (C) 2018-2020, 2022-2023, 2025-2026 Aurélien PIERRE.
24 Copyright (C) 2018 Edgardo Hoszowski.
25 Copyright (C) 2018 Maurizio Paglia.
26 Copyright (C) 2018 rawfiner.
27 Copyright (C) 2019 Andreas Schneider.
28 Copyright (C) 2020 Aldric Renaudin.
29 Copyright (C) 2020, 2022 Diederik Ter Rahe.
30 Copyright (C) 2020 Hubert Kowalski.
31 Copyright (C) 2020-2021 Ralf Brown.
32 Copyright (C) 2022 Hanno Schwalm.
33 Copyright (C) 2022 Martin Bařinka.
34 Copyright (C) 2022 Philipp Lutz.
35
36 darktable is free software: you can redistribute it and/or modify
37 it under the terms of the GNU General Public License as published by
38 the Free Software Foundation, either version 3 of the License, or
39 (at your option) any later version.
40
41 darktable is distributed in the hope that it will be useful,
42 but WITHOUT ANY WARRANTY; without even the implied warranty of
43 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
44 GNU General Public License for more details.
45
46 You should have received a copy of the GNU General Public License
47 along with darktable. If not, see <http://www.gnu.org/licenses/>.
48*/
49#ifdef HAVE_CONFIG_H
50#include "system/macros.h"
51#include "system/mem_alloc.h"
53#include "common/logging.h"
54#include "system/openmp.h"
55#include "system/simd.h"
58#include "config.h"
59#endif
60#include "widgets/bauhaus.h"
61#include "common/imagebuf.h"
62#include "common/opencl.h"
63#include "develop/develop.h"
64#include "develop/imageop.h"
66#include "develop/imageop_gui.h"
67#include "develop/tiling.h"
68
69#include "gui/presets.h"
70#include "iop/iop_api.h"
71#include <assert.h>
72#include <math.h>
73#include <stdlib.h>
74#include <string.h>
75
76#include <gtk/gtk.h>
77#include <inttypes.h>
78
80
81#define MAXR 12
82
84{
85 float radius; // $MIN: 0.0 $MAX: 99.0 $DEFAULT: 2.0
86 float amount; // $MIN: 0.0 $MAX: 2.0 $DEFAULT: 0.5
87 float threshold; // $MIN: 0.0 $MAX: 100.0 $DEFAULT: 0.5
89
94
99
106
107
108const char *name()
109{
110 return C_("modulename", "sharpen");
111}
112
114{
115 return IOP_GROUP_SHARPNESS;
116}
117
122
124{
125 return IOP_CS_LAB;
126}
127
128const char **description(struct dt_iop_module_t *self)
129{
130 return dt_iop_set_description(self, _("sharpen the details in the image using a standard UnSharp Mask (USM)"),
131 _("corrective"),
132 _("linear or non-linear, Lab, display or scene-referred"),
133 _("frequential, Lab"),
134 _("quasi-linear, Lab, display or scene-referred"));
135}
136
138{
139 dt_iop_sharpen_params_t tmp = (dt_iop_sharpen_params_t){ 2.0, 0.5, 0.5 };
140 // add the preset.
141 dt_gui_presets_add_generic(_("sharpen"), self->op,
142 self->version(), &tmp, sizeof(dt_iop_sharpen_params_t), 1);
143 // restrict to raw images
144 dt_gui_presets_update_ldr(_("sharpen"), self->op,
145 self->version(), FOR_RAW);
146}
147
149static float *const init_gaussian_kernel(const int rad, const size_t mat_size, const float sigma2)
150{
151 float weight = 0.0f;
152 float *const mat = dt_pixelpipe_cache_alloc_align_float_cache(mat_size, 0);
153 if(IS_NULL_PTR(mat)) return NULL;
154 memset(mat, 0, sizeof(float) * mat_size);
155 for(int l = -rad; l <= rad; l++) weight += mat[l + rad] = expf(-l * l / (2.f * sigma2));
156 for(int l = -rad; l <= rad; l++) mat[l + rad] /= weight;
157 return mat;
158}
159
160#ifdef HAVE_OPENCL
161int 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)
162{
163 const dt_iop_roi_t *const roi_in = &piece->roi_in;
166 cl_mem dev_m = NULL;
167 cl_mem dev_tmp = NULL;
168 cl_int err = -999;
169
170 const int devid = pipe->devid;
171 const int width = roi_in->width;
172 const int height = roi_in->height;
173 const int rad = MIN(MAXR, ceilf(d->radius * roi_in->scale));
174 const int wd = 2 * rad + 1;
175 float *mat = NULL;
176
177 if(rad == 0)
178 {
179 size_t origin[] = { 0, 0, 0 };
180 size_t region[] = { width, height, 1 };
181 err = dt_opencl_enqueue_copy_image(devid, dev_in, dev_out, origin, origin, region);
182 if(err != CL_SUCCESS) goto error;
183 return TRUE;
184 }
185
186 // special case handling: very small image with one or two dimensions below 2*rad+1 => no sharpening,
187 // normally not needed for OpenCL but implemented here for identity with CPU code path
188 if(width < 2 * rad + 1 || height < 2 * rad + 1)
189 {
190 size_t origin[] = { 0, 0, 0 };
191 size_t region[] = { width, height, 1 };
192 err = dt_opencl_enqueue_copy_image(devid, dev_in, dev_out, origin, origin, region);
193 if(err != CL_SUCCESS) goto error;
194 return TRUE;
195 }
196
197 const float sigma2 = (1.0f / (2.5 * 2.5)) * (d->radius * roi_in->scale)
198 * (d->radius * roi_in->scale);
199 mat = init_gaussian_kernel(rad, wd, sigma2);
200 if(IS_NULL_PTR(mat)) goto error;
201
202 int hblocksize;
204 = (dt_opencl_local_buffer_t){ .xoffset = 2 * rad, .xfactor = 1, .yoffset = 0, .yfactor = 1,
205 .cellsize = sizeof(float), .overhead = 0,
206 .sizex = 1 << 16, .sizey = 1 };
207
208 if(dt_opencl_local_buffer_opt(devid, gd->kernel_sharpen_hblur, &hlocopt))
209 hblocksize = hlocopt.sizex;
210 else
211 hblocksize = 1;
212
213 int vblocksize;
215 = (dt_opencl_local_buffer_t){ .xoffset = 1, .xfactor = 1, .yoffset = 2 * rad, .yfactor = 1,
216 .cellsize = sizeof(float), .overhead = 0,
217 .sizex = 1, .sizey = 1 << 16 };
218
219 if(dt_opencl_local_buffer_opt(devid, gd->kernel_sharpen_vblur, &vlocopt))
220 vblocksize = vlocopt.sizey;
221 else
222 vblocksize = 1;
223
224
225 const size_t bwidth = ROUNDUP(width, hblocksize);
226 const size_t bheight = ROUNDUP(height, vblocksize);
227
228 size_t sizes[3];
229 size_t local[3];
230
231 dev_tmp = dt_opencl_alloc_device(devid, width, height, sizeof(float) * 4);
232 if(IS_NULL_PTR(dev_tmp)) goto error;
233
234 dev_m = dt_opencl_copy_host_to_device_constant(devid, sizeof(float) * wd, mat);
235 if(IS_NULL_PTR(dev_m)) goto error;
236
237 /* horizontal blur */
238 sizes[0] = bwidth;
239 sizes[1] = ROUNDUPDHT(height, devid);
240 sizes[2] = 1;
241 local[0] = hblocksize;
242 local[1] = 1;
243 local[2] = 1;
244 dt_opencl_set_kernel_arg(devid, gd->kernel_sharpen_hblur, 0, sizeof(cl_mem), (void *)&dev_in);
245 dt_opencl_set_kernel_arg(devid, gd->kernel_sharpen_hblur, 1, sizeof(cl_mem), (void *)&dev_out);
246 dt_opencl_set_kernel_arg(devid, gd->kernel_sharpen_hblur, 2, sizeof(cl_mem), (void *)&dev_m);
247 dt_opencl_set_kernel_arg(devid, gd->kernel_sharpen_hblur, 3, sizeof(int), (void *)&rad);
248 dt_opencl_set_kernel_arg(devid, gd->kernel_sharpen_hblur, 4, sizeof(int), (void *)&width);
249 dt_opencl_set_kernel_arg(devid, gd->kernel_sharpen_hblur, 5, sizeof(int), (void *)&height);
250 dt_opencl_set_kernel_arg(devid, gd->kernel_sharpen_hblur, 6, sizeof(int), (void *)&hblocksize);
251 dt_opencl_set_kernel_arg(devid, gd->kernel_sharpen_hblur, 7, (hblocksize + 2 * rad) * sizeof(float), NULL);
252 err = dt_opencl_enqueue_kernel_2d_with_local(devid, gd->kernel_sharpen_hblur, sizes, local);
253 if(err != CL_SUCCESS) goto error;
254
255 /* vertical blur */
256 sizes[0] = ROUNDUPDWD(width, devid);
257 sizes[1] = bheight;
258 sizes[2] = 1;
259 local[0] = 1;
260 local[1] = vblocksize;
261 local[2] = 1;
262 dt_opencl_set_kernel_arg(devid, gd->kernel_sharpen_vblur, 0, sizeof(cl_mem), (void *)&dev_out);
263 dt_opencl_set_kernel_arg(devid, gd->kernel_sharpen_vblur, 1, sizeof(cl_mem), (void *)&dev_tmp);
264 dt_opencl_set_kernel_arg(devid, gd->kernel_sharpen_vblur, 2, sizeof(cl_mem), (void *)&dev_m);
265 dt_opencl_set_kernel_arg(devid, gd->kernel_sharpen_vblur, 3, sizeof(int), (void *)&rad);
266 dt_opencl_set_kernel_arg(devid, gd->kernel_sharpen_vblur, 4, sizeof(int), (void *)&width);
267 dt_opencl_set_kernel_arg(devid, gd->kernel_sharpen_vblur, 5, sizeof(int), (void *)&height);
268 dt_opencl_set_kernel_arg(devid, gd->kernel_sharpen_vblur, 6, sizeof(int), (void *)&vblocksize);
269 dt_opencl_set_kernel_arg(devid, gd->kernel_sharpen_vblur, 7, (vblocksize + 2 * rad) * sizeof(float), NULL);
270 err = dt_opencl_enqueue_kernel_2d_with_local(devid, gd->kernel_sharpen_vblur, sizes, local);
271 if(err != CL_SUCCESS) goto error;
272
273 /* mixing tmp and in -> out */
274 sizes[0] = ROUNDUPDWD(width, devid);
275 sizes[1] = ROUNDUPDHT(height, devid);
276 sizes[2] = 1;
277 dt_opencl_set_kernel_arg(devid, gd->kernel_sharpen_mix, 0, sizeof(cl_mem), (void *)&dev_in);
278 dt_opencl_set_kernel_arg(devid, gd->kernel_sharpen_mix, 1, sizeof(cl_mem), (void *)&dev_tmp);
279 dt_opencl_set_kernel_arg(devid, gd->kernel_sharpen_mix, 2, sizeof(cl_mem), (void *)&dev_out);
280 dt_opencl_set_kernel_arg(devid, gd->kernel_sharpen_mix, 3, sizeof(int), (void *)&width);
281 dt_opencl_set_kernel_arg(devid, gd->kernel_sharpen_mix, 4, sizeof(int), (void *)&height);
282 dt_opencl_set_kernel_arg(devid, gd->kernel_sharpen_mix, 5, sizeof(float), (void *)&d->amount);
283 dt_opencl_set_kernel_arg(devid, gd->kernel_sharpen_mix, 6, sizeof(float), (void *)&d->threshold);
284 err = dt_opencl_enqueue_kernel_2d(devid, gd->kernel_sharpen_mix, sizes);
285 if(err != CL_SUCCESS) goto error;
286
290 return TRUE;
291
292error:
296 dt_print(DT_DEBUG_OPENCL, "[opencl_sharpen] couldn't enqueue kernel! %d\n", err);
297 return FALSE;
298}
299#endif
300
301
302void 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)
303{
304 const dt_iop_roi_t *const roi_in = &piece->roi_in;
306 const int rad = MIN(MAXR, ceilf(d->radius * roi_in->scale));
307
308 tiling->factor = 2.1f; // in + out + tmprow
309 tiling->factor_cl = 3.0f; // in + out + tmp
310 tiling->maxbuf = 1.0f;
311 tiling->overhead = 0;
312 tiling->overlap = rad;
313 tiling->xalign = 1;
314 tiling->yalign = 1;
315 return;
316}
317
319int process(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, const void *const ivoid,
320 void *const ovoid)
321{
322 const dt_iop_roi_t *const roi_in = &piece->roi_in;
323 const dt_iop_roi_t *const roi_out = &piece->roi_out;
324 const dt_iop_sharpen_data_t *const data = (dt_iop_sharpen_data_t *)piece->data;
325 const int rad = MIN(MAXR, ceilf(data->radius * roi_in->scale));
326 // Special case handling: very small image with one or two dimensions below 2*rad+1 treat as no sharpening and just
327 // pass through. This avoids handling of all kinds of border cases below.
328 if(rad == 0 ||
329 (roi_out->width < 2 * rad + 1 || roi_out->height < 2 * rad + 1))
330 {
331 dt_iop_image_copy_by_size(ovoid, ivoid, roi_out->width, roi_out->height, 4);
332 return 0;
333 }
334
335 float *restrict tmp; // one row per thread
336 size_t padded_size;
337 if (dt_iop_alloc_image_buffers(self, roi_in, roi_out,
338 1 | DT_IMGSZ_WIDTH | DT_IMGSZ_PERTHREAD, &tmp, &padded_size,
339 0))
340 {
341 dt_iop_copy_image_roi(ovoid, ivoid, 4, roi_in, roi_out, TRUE);
342 return 1;
343 }
344
345 const int wd = 2 * rad + 1;
346 const int wd4 = (wd & 3) ? (wd >> 2) + 1 : wd >> 2;
347
348 const size_t mat_size = (size_t)4 * wd4;
349 const float sigma2 = (1.0f / (2.5 * 2.5)) * (data->radius * roi_in->scale)
350 * (data->radius * roi_in->scale);
351 float *const mat = init_gaussian_kernel(rad, mat_size, sigma2);
352 if(IS_NULL_PTR(mat))
353 {
355 dt_iop_copy_image_roi(ovoid, ivoid, 4, roi_in, roi_out, TRUE);
356 return 1;
357 }
358
359 const float *const restrict in = (float*)ivoid;
360 const size_t width = roi_out->width;
362 for(int j = 0; j < roi_out->height; j++)
363 {
364 // We skip the top and bottom 'rad' rows because the kernel would extend beyond the edge of the image, resulting
365 // in an incomplete summation.
366 if (j < rad || j >= roi_out->height - rad)
367 {
368 // fill in the top/bottom border with unchanged luma values from the input image.
369 const float *const restrict row_in = in + (size_t)4 * j * width;
370 float *const restrict row_out = ((float*)ovoid) + (size_t)4 * j * width;
371 memcpy(row_out, row_in, 4 * sizeof(float) * width);
372 continue;
373 }
374 // Get a thread-local temporary buffer for processing the current row of the image.
375 float *const restrict temp_buf = dt_get_perthread(tmp, padded_size);
376 // vertically blur the pixels of the current row into the temp buffer
377 const size_t start_row = j-rad;
378 const size_t end_row = j+rad;
379 // do the bulk of the row four at a time
380 for(int i = 0; i < width; i += 4)
381 {
382 dt_aligned_pixel_t sum = { 0.0f };
383 for(int k = start_row; k <= end_row; k++)
384 {
385 const int k_adj = k - (j-rad);
386 for_four_channels(c,aligned(in))
387 sum[c] += mat[k_adj] * in[4*(k*width+i+c)];
388 }
389 float *const vblurred = temp_buf + i;
390 for_four_channels(c,aligned(vblurred))
391 vblurred[c] = sum[c];
392 }
393 // do the leftover 0-3 pixels of the row
394 for(int i = width & ~3; i < width; i++)
395 {
396 float sum = 0.0f;
397 for(int k = start_row; k <= end_row; k++)
398 {
399 const int k_adj = k - (j-rad);
400 sum += mat[k_adj] * in[4*(k*width+i)];
401 }
402 temp_buf[i] = sum;
403 }
404
405 // now horizontally blur the already vertically-blurred pixels from the temp buffer to the final output buffer
406 // we can skip the left-most and right-most pixels for the same reason as we skipped the top and bottom borders.
407 float *const restrict row_out = ((float*)ovoid) + (size_t)4 * j * width;
408 for(int i = 0; i < rad; i++)
409 copy_pixel(row_out + 4*i, in + 4*(j*width+i)); //copy unsharpened border pixel
410 const float threshold = data->threshold;
411 const float amount = data->amount;
412 for(int i = rad; i < roi_out->width - rad; i++)
413 {
414 float sum = 0.0f;
415 for(int k = i-rad; k <= i+rad; k++)
416 {
417 const int k_adj = k - (i-rad);
418 sum += mat[k_adj] * temp_buf[k];
419 }
420 // subtract the blurred pixel's luma from the original input pixel's luma
421 const size_t index = 4 * (j * width + i);
422 const float diff = in[index] - sum;
423 const float absdiff = fabs(diff);
424 const float detail = (absdiff > threshold) ? copysignf(MAX(absdiff - threshold, 0.0f), diff) : 0.0f;
425 row_out[4*i] = in[index] + detail * amount;
426 row_out[4*i + 1] = in[index + 1];
427 row_out[4*i + 2] = in[index + 2];
428 }
429 for(int i = roi_out->width - rad; i < roi_out->width; i++)
430 copy_pixel(row_out + 4*i, in + 4*(j*width+i)); //copy unsharpened border pixel
431 }
432
435
437 dt_iop_alpha_copy(ivoid, ovoid, roi_out->width, roi_out->height);
438 return 0;
439}
440
443{
446
447 // actually need to increase the mask to fit 2.5 sigma inside
448 d->radius = 2.5f * p->radius;
449 d->amount = p->amount;
450 d->threshold = p->threshold;
451}
452
454{
456 piece->data_size = sizeof(dt_iop_sharpen_data_t);
457}
458
460{
461 dt_free_align(piece->data);
462 piece->data = NULL;
463}
464
466{
467 const int program = 7; // sharpen.cl, from programs.conf
470 if(IS_NULL_PTR(gd)) return;
471 module->data = gd;
472 gd->kernel_sharpen_hblur = dt_opencl_create_kernel(program, "sharpen_hblur");
473 gd->kernel_sharpen_vblur = dt_opencl_create_kernel(program, "sharpen_vblur");
474 gd->kernel_sharpen_mix = dt_opencl_create_kernel(program, "sharpen_mix");
475}
476
485
486void gui_init(struct dt_iop_module_t *self)
487{
489
490 g->radius = dt_bauhaus_slider_from_params(self, N_("radius"));
491 dt_bauhaus_slider_set_soft_max(g->radius, 8.0);
493 gtk_widget_set_tooltip_text(g->radius, _("spatial extent of the unblurring"));
494
495 g->amount = dt_bauhaus_slider_from_params(self, N_("amount"));
497 gtk_widget_set_tooltip_text(g->amount, _("strength of the sharpen"));
498
499 g->threshold = dt_bauhaus_slider_from_params(self, N_("threshold"));
500 dt_bauhaus_slider_set_digits(g->threshold, 3);
501 gtk_widget_set_tooltip_text(g->threshold, _("threshold to activate sharpen"));
502}
503
504#undef MAXR
505
506// clang-format off
507// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
508// vim: shiftwidth=2 expandtab tabstop=2 cindent
509// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
510// 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 dt_bauhaus_slider_set_digits(GtkWidget *widget, int val)
Definition bauhaus.c:3343
void dt_bauhaus_slider_set_soft_max(GtkWidget *widget, float val)
Definition bauhaus.c:1474
@ IOP_CS_LAB
struct _GtkWidget GtkWidget
GtkWidget, opaque, spelled exactly as GTK spells it.
Definition colorspaces.h:98
const float threshold
void dt_iop_params_t
Definition dev_history.h:43
@ DT_DEV_PIXELPIPE_DISPLAY_MASK
Definition develop.h:123
static void weight(const float *c1, const float *c2, const float sharpen, dt_aligned_pixel_t weight)
Definition eaw.c:29
void dt_gui_presets_update_ldr(const char *name, dt_dev_operation_t op, const int32_t version, const int ldrflag)
void dt_gui_presets_add_generic(const char *name, dt_dev_operation_t op, const int32_t version, const void *params, const int32_t params_size, const int32_t enabled)
@ FOR_RAW
int dt_iop_alloc_image_buffers(struct dt_iop_module_t *const module, const struct dt_iop_roi_t *const roi_in, const struct dt_iop_roi_t *const roi_out,...)
Definition imagebuf.c:35
void dt_iop_copy_image_roi(float *const __restrict__ out, const float *const __restrict__ in, const size_t ch, const dt_iop_roi_t *const __restrict__ roi_in, const dt_iop_roi_t *const __restrict__ roi_out, const int zero_pad)
Definition imagebuf.c:163
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:91
#define DT_IMGSZ_WIDTH
Definition imagebuf.h:67
#define DT_IMGSZ_PERTHREAD
Definition imagebuf.h:61
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:1893
@ IOP_FLAGS_DEPRECATED
Definition imageop.h:187
@ IOP_FLAGS_SUPPORTS_BLENDING
Definition imageop.h:186
@ IOP_FLAGS_ALLOW_TILING
Definition imageop.h:188
@ IOP_GROUP_SHARPNESS
Definition imageop.h:160
GtkWidget * dt_bauhaus_slider_from_params(dt_iop_module_t *self, const char *param)
#define IOP_GUI_ALLOC(module)
Definition imageop_gui.h:93
void *const ovoid
@ DT_DEBUG_OPENCL
Definition logging.h:57
void dt_print(dt_debug_thread_t thread, const char *msg,...) __attribute__((format(printf
Print to stdout when thread is enabled, prefixed with seconds since startup.
float *const restrict const size_t k
#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 dt_free_align(ptr)
Release memory from dt_alloc_align() and set ptr to NULL.
Definition mem_alloc.h:214
static void * dt_calloc_align(size_t size)
dt_alloc_align() followed by a zero fill.
Definition mem_alloc.h:225
#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
#define DT_MODULE_INTROSPECTION(MODVER, PARAMSTYPE)
DT_MODULE() for a module whose params struct is introspected.
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(const int devid, const int width, const int height, const int bpp)
Definition opencl.c:2894
int dt_opencl_create_kernel(const int prog, const char *name)
Definition opencl.c:2448
void * dt_opencl_copy_host_to_device_constant(const int devid, const size_t size, void *host)
Definition opencl.c:2750
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:2679
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_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)
#define dt_get_perthread(buf, padsize)
void commit_params(struct dt_iop_module_t *self, dt_iop_params_t *p1, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Definition sharpen.c:441
const char ** description(struct dt_iop_module_t *self)
Definition sharpen.c:128
int default_group()
Definition sharpen.c:113
__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 ivoid, void *const ovoid)
Definition sharpen.c:319
void init_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Definition sharpen.c:453
const char * name()
Definition sharpen.c:108
void gui_init(struct dt_iop_module_t *self)
Definition sharpen.c:486
#define MAXR
Definition sharpen.c:81
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 sharpen.c:302
void cleanup_global(dt_iop_module_so_t *module)
Definition sharpen.c:477
int default_colorspace(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece)
Definition sharpen.c:123
int flags()
Definition sharpen.c:118
void init_presets(dt_iop_module_so_t *self)
Definition sharpen.c:137
void cleanup_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Definition sharpen.c:459
void init_global(dt_iop_module_so_t *module)
Definition sharpen.c:465
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 sharpen.c:161
static __DT_CLONE_TARGETS__ float *const init_gaussian_kernel(const int rad, const size_t mat_size, const float sigma2)
Definition sharpen.c:149
static void copy_pixel(float *const __restrict__ out, const float *const __restrict__ in)
Definition simd.h:217
DT_ALIGNED_PIXEL float dt_aligned_pixel_t[4]
Definition simd.h:53
#define for_four_channels(_var,...)
Definition simd.h:89
struct dt_iop_module_t *void * data
dt_dev_operation_t op
Definition imageop.h:235
dt_iop_global_data_t * data
Definition imageop.h:238
dt_iop_global_data_t * global_data
Definition imageop.h:337
Region of interest passed through the pixelpipe.
Definition format.h:49
double scale
Definition format.h:51
int width
Definition format.h:50
int height
Definition format.h:50
GtkWidget * threshold
Definition sharpen.c:92
#define __DT_CLONE_TARGETS__
#define MIN(a, b)
Definition thinplate.c:32
#define MAX(a, b)
Definition thinplate.c:29