Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
censorize.c
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2020-2021, 2023, 2025-2026 Aurélien PIERRE.
4 Copyright (C) 2021 Hubert Kowalski.
5 Copyright (C) 2021-2022 Pascal Obry.
6 Copyright (C) 2021 Ralf Brown.
7 Copyright (C) 2022 Diederik Ter Rahe.
8 Copyright (C) 2022 Hanno Schwalm.
9 Copyright (C) 2022 Martin Bařinka.
10 Copyright (C) 2022 Philipp Lutz.
11
12 darktable is free software: you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation, either version 3 of the License, or
15 (at your option) any later version.
16
17 darktable is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
21
22 You should have received a copy of the GNU General Public License
23 along with darktable. If not, see <http://www.gnu.org/licenses/>.
24*/
25
26#ifdef HAVE_CONFIG_H
27#include "system/macros.h"
28#include "system/mem_alloc.h"
30#include "system/openmp.h"
31#include "system/simd.h"
34#include "config.h"
35#endif
36#include "pixel/gaussian.h"
37#include "common/imagebuf.h"
38#include "develop/develop.h"
39#include "develop/imageop.h"
41#include "develop/imageop_gui.h"
42#include "iop/noise_generator.h"
43
44#include "iop/iop_api.h"
45#include <assert.h>
46#include <gtk/gtk.h>
47#include <math.h>
48#include <stdlib.h>
49#include <string.h>
50
51#include <inttypes.h>
52
54
56{
57 float radius_1; // $MIN: 0.0 $MAX: 500.0 $DEFAULT: 0.0 $DESCRIPTION: "input blur radius"
58 float pixelate; // $MIN: 0.0 $MAX: 500.0 $DEFAULT: 0.0 $DESCRIPTION: "pixellation radius"
59 float radius_2; // $MIN: 0.0 $MAX: 500.0 $DEFAULT: 0.0 $DESCRIPTION: "output blur radius"
60 float noise; // $MIN: 0.0 $MAX: 1.0 $DEFAULT: 0.0 $DESCRIPTION: "noise level"
62
63
68
70
75
76typedef struct point_t
77{
78 size_t x, y;
80
81const char *
83{
84 return _("censorize");
85}
86
87const char **description(struct dt_iop_module_t *self)
88{
89 return dt_iop_set_description(self, _("censorize license plates and body parts for privacy"),
90 _("creative"),
91 _("linear or non-linear, RGB, scene-referred"),
92 _("frequential, RGB"),
93 _("special, RGB, scene-referred"));
94}
95
100
102{
103 return IOP_GROUP_EFFECTS;
104}
105
107{
108 return IOP_CS_RGB;
109}
110
112static inline void make_noise(float *const output, const float noise, const size_t width, const size_t height)
113{
114 __OMP_PARALLEL_FOR_SIMD__(aligned(output:64) collapse(2))
115 for(size_t i = 0; i < height; i++)
116 for(size_t j = 0; j < width; j++)
117 {
118 // Init random number generator
119 uint32_t DT_ALIGNED_ARRAY state[4] = { splitmix32(j + 1), splitmix32((j + 1) * (i + 3)), splitmix32(1337), splitmix32(666) };
124
125 const size_t index = (i * width + j) * 4;
126 float *const restrict pix_out = __builtin_assume_aligned(output + index, 16);
127 const float norm = pix_out[1];
128
129 // create statistical noise
130 const float epsilon = gaussian_noise(norm, noise * norm, i % 2 || j % 2, state) / norm;
131
132 // add noise to output
133 for(size_t c = 0; c < 3; c++) pix_out[c] = fmaxf(pix_out[c] * epsilon, 0.f);
134 }
135}
136
137
139int process(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, const void *const ivoid,
140 void *const ovoid)
141{
142 const dt_iop_roi_t *const roi_in = &piece->roi_in;
143 const dt_iop_roi_t *const roi_out = &piece->roi_out;
144
146 const float *const restrict in = DT_IS_ALIGNED((const float *const restrict)ivoid);
147 float *const restrict out = DT_IS_ALIGNED((float *const restrict)ovoid);
148
149 const int width = roi_in->width;
150 const int height = roi_in->height;
151 const int ch = 4;
152
153 float *const restrict temp = dt_pixelpipe_cache_alloc_align_float((size_t)width * height * ch, pipe);
154 if(IS_NULL_PTR(temp)) return 1;
155
156 const float module_scale = dt_dev_get_module_scale(pipe, roi_in);
157 const float sigma_1 = data->radius_1 / module_scale;
158 const float sigma_2 = data->radius_2 / module_scale;
159 const size_t pixel_radius = data->pixelate / module_scale;
160
161 // used to adjuste blur level depending on size. Don't amplify noise if magnified > 100%
162 const float scale = fmaxf(module_scale, 1.f);
163 const float noise = data->noise / scale;
164
165 dt_aligned_pixel_t RGBmax, RGBmin;
166 for(int k = 0; k < 4; k++)
167 {
168 RGBmax[k] = INFINITY;
169 RGBmin[k] = 0.f;
170 }
171
172 const float *restrict input = in;
173 float *restrict output = out;
174
175 // first blurring step
176 if(sigma_1 != 0.f)
177 {
178 dt_gaussian_t *g = dt_gaussian_init(width, height, ch, RGBmax, RGBmin, sigma_1, 0);
179 if(IS_NULL_PTR(g))
180 {
182 return 1;
183 }
184 dt_gaussian_blur_4c(g, input, output);
186
187 input = output;
188 }
189
190 output = temp;
191
192 // pixelate
193 if(pixel_radius != 0)
194 {
195 const size_t pixels_x = width / (2 * pixel_radius);
196 const size_t pixels_y = height / (2 * pixel_radius);
197 __OMP_PARALLEL_FOR__(collapse(2))
198 for(size_t j = 0; j < pixels_y + 1; j++)
199 for(size_t i = 0; i < pixels_x + 1; i++)
200 {
201 // get the top left coordinate of the big pixel
202 const point_t tl = { CLAMP(2 * pixel_radius * i, 0, width - 1),
203 CLAMP(2 * pixel_radius * j, 0, height - 1) };
204 // get the center of the big pixel
205 const point_t cc = { CLAMP(tl.x + pixel_radius, 0, width - 1),
206 CLAMP(tl.y + pixel_radius, 0, height - 1) };
207 // get the bottom right coordinate of the big pixel
208 const point_t br = { CLAMP(cc.x + pixel_radius, 0, width - 1),
209 CLAMP(cc.y + pixel_radius, 0, height - 1) };
210
211 // get the bounding box + center point coordinates
212 const point_t box[5] = { tl, { br.x, tl.y }, cc, { tl.x, br.y }, br };
213
214 // find the average color over the big pixel
215 dt_aligned_pixel_t RGB = { 0.f };
216 for(size_t k = 0; k < 5; k++)
217 {
218 const float *const restrict pix_in = __builtin_assume_aligned(input + (width * box[k].y + box[k].x) * 4, 16);
220 RGB[c] += pix_in[c] / 5.f;
221 }
222
223 // paint the big pixel with solid color == average
224 for(size_t jj = tl.y; jj < br.y; jj++)
225 for(size_t ii = tl.x; ii < br.x; ii++)
226 {
227 float *const restrict pix_out = __builtin_assume_aligned(output + (jj * width + ii) * 4, 16);
229 pix_out[c] = RGB[c];
230 }
231 }
232
233 input = output;
234 }
235
236 // second blurring step
237 if(sigma_2 != 0.f)
238 {
239 output = out;
240
241 if(noise != 0.f)
242 make_noise(output, noise, width, height);
243
244 dt_gaussian_t *g = dt_gaussian_init(width, height, ch, RGBmax, RGBmin, sigma_2, 0);
245 if(IS_NULL_PTR(g))
246 {
248 return 1;
249 }
250 dt_gaussian_blur_4c(g, input, output);
252 }
253 else
254 {
255 output = out;
256 dt_simd_memcpy(input, output, (size_t)width * height * ch);
257 }
258
259 if(noise != 0.f)
260 make_noise(output, noise, width, height);
261
263 dt_iop_alpha_copy(ivoid, ovoid, roi_out->width, roi_out->height);
264
266 return 0;
267}
268
269
270// OpenCL not implemented yet, but the following only needs a slight modification to get it working
271#if FALSE
272int 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)
273{
274 const dt_iop_roi_t *const roi_in = &piece->roi_in;
275 const dt_iop_roi_t *const roi_out = &piece->roi_out;
278
279 cl_int err = -999;
280 const int devid = pipe->devid;
281
282 const int width = roi_in->width;
283 const int height = roi_in->height;
284 const int channels = piece->dsc_in.channels;
285
286 const float radius_1 = fmax(0.1f, d->radius_1);
287 const float sigma = radius_1 * roi_in->scale;
288 const float saturation = d->saturation;
289 const int order = d->order;
290 const int unbound = d->unbound;
291
292 cl_mem dev_cm = NULL;
293 cl_mem dev_ccoeffs = NULL;
294 cl_mem dev_lm = NULL;
295 cl_mem dev_lcoeffs = NULL;
296 cl_mem dev_tmp = NULL;
297
298 dt_gaussian_cl_t *g = NULL;
299 dt_bilateral_cl_t *b = NULL;
300
301 float RGBmax[] = { 100.0f, 128.0f, 128.0f, 1.0f };
302 float RGBmin[] = { 0.0f, -128.0f, -128.0f, 0.0f };
303
304 if(unbound)
305 {
306 for(int k = 0; k < 4; k++) RGBmax[k] = INFINITY;
307 for(int k = 0; k < 4; k++) RGBmin[k] = -INFINITY;
308 }
309
310 if(d->lowpass_algo == LOWPASS_ALGO_GAUSSIAN)
311 {
312 g = dt_gaussian_init_cl(devid, width, height, channels, RGBmax, RGBmin, sigma, order);
313 if(IS_NULL_PTR(g)) goto error;
314 err = dt_gaussian_blur_cl(g, dev_in, dev_out);
315 if(err != CL_SUCCESS) goto error;
317 g = NULL;
318 }
319 else
320 {
321 const float sigma_r = 100.0f; // does not depend on scale
322 const float sigma_s = sigma;
323 const float detail = -1.0f; // we want the bilateral base layer
324
326 if(IS_NULL_PTR(b)) goto error;
327 err = dt_bilateral_splat_cl(b, dev_in);
328 if(err != CL_SUCCESS) goto error;
329 err = dt_bilateral_blur_cl(b);
330 if(err != CL_SUCCESS) goto error;
331 err = dt_bilateral_slice_cl(b, dev_in, dev_out, detail);
332 if(err != CL_SUCCESS) goto error;
334 b = NULL; // make sure we don't clean it up twice
335 }
336
337 dev_tmp = dt_opencl_alloc_device(devid, width, height, 4 * sizeof(float));
338 if(IS_NULL_PTR(dev_tmp)) goto error;
339
340 dev_cm = dt_opencl_copy_host_to_device(devid, d->ctable, 256, 256, sizeof(float));
341 if(IS_NULL_PTR(dev_cm)) goto error;
342
343 dev_ccoeffs = dt_opencl_copy_host_to_device_constant(devid, sizeof(float) * 3, d->cunbounded_coeffs);
344 if(IS_NULL_PTR(dev_ccoeffs)) goto error;
345
346 dev_lm = dt_opencl_copy_host_to_device(devid, d->ltable, 256, 256, sizeof(float));
347 if(IS_NULL_PTR(dev_lm)) goto error;
348
349 dev_lcoeffs = dt_opencl_copy_host_to_device_constant(devid, sizeof(float) * 3, d->lunbounded_coeffs);
350 if(IS_NULL_PTR(dev_lcoeffs)) goto error;
351
352 size_t origin[] = { 0, 0, 0 };
353 size_t region[] = { width, height, 1 };
354 err = dt_opencl_enqueue_copy_image(devid, dev_out, dev_tmp, origin, origin, region);
355 if(err != CL_SUCCESS) goto error;
356
357 const size_t sizes[] = { ROUNDUPDWD(width, devid), ROUNDUPDHT(height, devid), 1 };
358 dt_opencl_set_kernel_arg(devid, gd->kernel_lowpass_mix, 0, sizeof(cl_mem), (void *)&dev_tmp);
359 dt_opencl_set_kernel_arg(devid, gd->kernel_lowpass_mix, 1, sizeof(cl_mem), (void *)&dev_out);
360 dt_opencl_set_kernel_arg(devid, gd->kernel_lowpass_mix, 2, sizeof(int), (void *)&width);
361 dt_opencl_set_kernel_arg(devid, gd->kernel_lowpass_mix, 3, sizeof(int), (void *)&height);
362 dt_opencl_set_kernel_arg(devid, gd->kernel_lowpass_mix, 4, sizeof(float), (void *)&saturation);
363 dt_opencl_set_kernel_arg(devid, gd->kernel_lowpass_mix, 5, sizeof(cl_mem), (void *)&dev_cm);
364 dt_opencl_set_kernel_arg(devid, gd->kernel_lowpass_mix, 6, sizeof(cl_mem), (void *)&dev_ccoeffs);
365 dt_opencl_set_kernel_arg(devid, gd->kernel_lowpass_mix, 7, sizeof(cl_mem), (void *)&dev_lm);
366 dt_opencl_set_kernel_arg(devid, gd->kernel_lowpass_mix, 8, sizeof(cl_mem), (void *)&dev_lcoeffs);
367 dt_opencl_set_kernel_arg(devid, gd->kernel_lowpass_mix, 9, sizeof(int), (void *)&unbound);
368
369 err = dt_opencl_enqueue_kernel_2d(devid, gd->kernel_lowpass_mix, sizes);
370 if(err != CL_SUCCESS) goto error;
371
373 dt_opencl_release_mem_object(dev_lcoeffs);
375 dt_opencl_release_mem_object(dev_ccoeffs);
377
378 return TRUE;
379
380error:
382 if(b) dt_bilateral_free_cl(b);
383
385 dt_opencl_release_mem_object(dev_lcoeffs);
387 dt_opencl_release_mem_object(dev_ccoeffs);
389 dt_print(DT_DEBUG_OPENCL, "[opencl_lowpass] couldn't enqueue kernel! %d\n", err);
390 return FALSE;
391}
392
393void 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)
394{
395 const dt_iop_roi_t *const roi_in = &piece->roi_in;
396 const dt_iop_roi_t *const roi_out = &piece->roi_out;
397 tiling->factor = 3.0f;
398 tiling->factor_cl = 5.0f;
399 tiling->maxbuf = 1.0f;
400 tiling->maxbuf_cl = 1.0f;
401 tiling->overhead = 0;
402 tiling->overlap = 0;
403 tiling->xalign = 1;
404 tiling->yalign = 1;
405}
406
408{
409 const int program = 6; // gaussian.cl, from programs.conf
412 module->data = gd;
413 gd->kernel_lowpass_mix = dt_opencl_create_kernel(program, "lowpass_mix");
414}
415
417{
420 dt_free(module->data);
421}
422
423#endif
424
425void gui_init(struct dt_iop_module_t *self)
426{
428
429 g->radius_1 = dt_bauhaus_slider_from_params(self, N_("radius_1"));
430
431 g->pixelate = dt_bauhaus_slider_from_params(self, N_("pixelate"));
432
433 g->radius_2 = dt_bauhaus_slider_from_params(self, N_("radius_2"));
434
435 g->noise = dt_bauhaus_slider_from_params(self, N_("noise"));
436
437 gtk_widget_set_tooltip_text(g->radius_1, _("radius of gaussian blur before pixellation"));
438 gtk_widget_set_tooltip_text(g->radius_2, _("radius of gaussian blur after pixellation"));
439 gtk_widget_set_tooltip_text(g->pixelate, _("radius of the intermediate pixellation"));
440 gtk_widget_set_tooltip_text(g->noise, _("amount of noise to add at the end"));
441}
442
443// clang-format off
444// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
445// vim: shiftwidth=2 expandtab tabstop=2 cindent
446// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
447// clang-format on
void cleanup_global(dt_iop_module_so_t *module)
Definition ashift.c:5871
void init_global(dt_iop_module_so_t *module)
Definition ashift.c:5859
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 ashift.c:3329
static void error(char *msg)
Definition ashift_lsd.c:202
#define TRUE
Definition ashift_lsd.c:162
#define FALSE
Definition ashift_lsd.c:158
float sigma_s
Definition bilateral.h:3
float sigma_r
Definition bilateral.h:3
void dt_bilateral_free_cl(dt_bilateral_cl_t *b)
Definition bilateralcl.c:60
cl_int dt_bilateral_slice_cl(dt_bilateral_cl_t *b, cl_mem in, cl_mem out, const float detail)
dt_bilateral_cl_t * dt_bilateral_init_cl(const int devid, const int width, const int height, const float sigma_s, const float sigma_r)
Definition bilateralcl.c:91
cl_int dt_bilateral_blur_cl(dt_bilateral_cl_t *b)
cl_int dt_bilateral_splat_cl(dt_bilateral_cl_t *b, cl_mem in)
const char ** description(struct dt_iop_module_t *self)
Definition censorize.c:87
int default_group()
Definition censorize.c:101
__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 censorize.c:139
struct point_t point_t
static __DT_CLONE_TARGETS__ void make_noise(float *const output, const float noise, const size_t width, const size_t height)
Definition censorize.c:112
const char * name()
Definition censorize.c:82
void gui_init(struct dt_iop_module_t *self)
Definition censorize.c:425
int default_colorspace(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece)
Definition censorize.c:106
int flags()
Definition censorize.c:96
dt_iop_censorize_params_t dt_iop_censorize_data_t
Definition censorize.c:69
@ IOP_CS_RGB
static const float x
struct _GtkWidget GtkWidget
GtkWidget, opaque, spelled exactly as GTK spells it.
Definition colorspaces.h:98
const dt_colormatrix_t dt_aligned_pixel_t out
static dt_aligned_pixel_t RGB
static unsigned int splitmix32(const unsigned long seed)
static float xoshiro128plus(uint state[4])
@ DT_DEV_PIXELPIPE_DISPLAY_MASK
Definition develop.h:123
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
cl_int dt_gaussian_blur_cl(dt_gaussian_cl_t *g, cl_mem dev_in, cl_mem dev_out)
Definition gaussian.c:453
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
static __DT_CLONE_TARGETS__ void dt_simd_memcpy(const float *const __restrict__ in, float *const __restrict__ out, const size_t num_elem)
Definition imagebuf.h:72
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
float dt_dev_get_module_scale(const dt_dev_pixelpipe_t *const pipe, const dt_iop_roi_t *const roi_in)
Definition imageop.c:134
@ IOP_FLAGS_INCLUDE_IN_STYLES
Definition imageop.h:185
@ IOP_FLAGS_SUPPORTS_BLENDING
Definition imageop.h:186
@ IOP_GROUP_EFFECTS
Definition imageop.h:161
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.
@ LOWPASS_ALGO_GAUSSIAN
Definition lowpass.c:78
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 DT_ALIGNED_ARRAY
Align an object on a cacheline boundary, so AVX2 can load it whole.
Definition mem_alloc.h:80
#define DT_IS_ALIGNED(x)
Promise the compiler that x is already cacheline-aligned, and return it.
Definition mem_alloc.h:51
#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_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
void * dt_opencl_copy_host_to_device(const int devid, void *host, const int width, const int height, const int bpp)
Definition opencl.c:2765
void dt_opencl_release_mem_object(cl_mem mem)
Definition opencl.c:2805
#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 __OMP_PARALLEL_FOR_SIMD__(...)
Definition openmp.h:96
#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
#define for_four_channels(_var,...)
Definition simd.h:89
const float uint32_t state[4]
const float sigma
const float noise
struct dt_iop_module_t *void * data
dt_iop_global_data_t * data
Definition imageop.h:238
Region of interest passed through the pixelpipe.
Definition format.h:49
int width
Definition format.h:50
int height
Definition format.h:50
size_t y
Definition censorize.c:78
size_t x
Definition censorize.c:78
#define __DT_CLONE_TARGETS__
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 atrous.c:664