57#define SLICE_HEIGHT 60
81#if !(defined(__x86_64__) || defined(__i386__))
82# define _mm_prefetch(where,hint)
85static inline float gh(
const float f)
90static inline int sign(
int a)
92 return (a > 0) - (a < 0);
96static int scatter(
const float scale,
const float scattering,
const int index1,
const int index2)
102 const int abs_i1 = abs(index1);
103 const int abs_i2 = abs(index2);
104 return scale * ((abs_i1 * abs_i1 * abs_i1 + 7.0 * abs_i1 * sqrt(abs_i2)) *
sign(index1) * scattering / 6.0 + index1);
111 const int search_radius =
params->search_radius;
112 const float scale =
params->scale;
113 const float scattering =
params->scattering;
114 int decimate =
params->decimate;
116 int n_patches = (2 * search_radius + 1) * (2 * search_radius + 1);
118 n_patches = (n_patches + 1) / 2;
119 *num_patches = n_patches ;
127 for (
int row_index = -search_radius; row_index <= search_radius; row_index++)
129 for (
int col_index = -search_radius; col_index <= search_radius; col_index++)
131 if (decimate && (++decimate & 1))
continue;
132 int r =
scatter(scale,scattering,row_index,col_index);
133 int c =
scatter(scale,scattering,col_index,row_index);
134 patches[patch_num].
rows =
r;
135 patches[patch_num].
cols = c;
136 if (
r > shift) shift =
r;
137 else if (-
r > shift) shift = -
r;
138 if (c > shift) shift = c;
139 else if (-c > shift) shift = -c;
140 patches[patch_num].
offset = (
r * stride + c * 4);
152 const int width = 2 * radius + 1;
162 const float diff = pix1[
i] - pix2[
i];
163 sum[
i] = diff * diff * norm[
i];
165 return sum[0] + sum[1] + sum[2];
170 const float*
const pix3,
const float* pix4,
176 const float diff1 = pix1[
i] - pix2[
i];
177 const float diff2 = pix3[
i] - pix4[
i];
178 sum[
i] = (diff1 * diff1 - diff2 * diff2) * norm[
i];
180 return sum[0] + sum[1] + sum[2];
183#if defined(CACHE_PIXDIFFS) || defined(CACHE_PIXDIFFS_SSE)
184static inline float get_pixdiff(
const float *
const col_sums,
const int radius,
const int row,
const int col)
186 const int stride = 2*(radius+1);
187 const int modrow = 1 + (
row + stride) % stride;
188 const float *
const pixrow = col_sums + (
SLICE_WIDTH + 2*radius)*modrow;
193#if defined(CACHE_PIXDIFFS) || defined(CACHE_PIXDIFFS_SSE)
194static inline void set_pixdiff(
float *
const col_sums,
const int radius,
const int row,
const int col,
197 const int stride = 2*(radius+1);
198 const int modrow = 1 + (
row + stride) % stride;
199 float *
const pixrow = col_sums + (
SLICE_WIDTH + 2*radius)*modrow;
204#if defined(CACHE_PIXDIFFS) || defined(CACHE_PIXDIFFS_SSE)
205static inline float pixdiff_column_sum(
const float *
const col_sums,
const int radius,
const int col)
208 float sum = col_sums[stride+col];
209 for (
int i = 2;
i <= (2*radius+1) ;
i++)
210 sum += col_sums[
i*stride+col];
216 const int row,
const int chunk_left,
const int chunk_right,
217 const int height,
const int width,
const int stride,
218 const int radius,
const float *
const norm)
226 const int scol = patch->
cols;
227 const int col_min = chunk_left -
MIN(radius,
MIN(chunk_left,chunk_left+scol));
228 const int col_max = chunk_right +
MIN(radius,
MIN(
width-chunk_right,
width-(chunk_right+scol)));
230 const int srow = patch->
rows;
233 for (
int col = chunk_left-radius-1; col <
MIN(col_min,chunk_right+radius); col++)
237 for(
int i =
row-radius;
i <=
row+radius;
i++)
238 set_pixdiff(col_sums,radius,
i,col,0.0f);
241 for (
int col = col_min; col < col_max; col++)
244 for (
int r = rmin;
r <= rmax;
r++)
246 const float *pixel = in +
r*stride + 4*col;
249 set_pixdiff(col_sums,radius,
r,col,diff);
256 for (
int col =
MAX(col_min,col_max); col < chunk_right + radius; col++)
260 for(
int i =
row-radius;
i <=
row+radius;
i++)
261 set_pixdiff(col_sums,radius,
i,col,0.0f);
275 for (
int incr = 1; incr < 10; incr++)
280 else if (plus_rem > best)
288 else if (minus_rem > best)
303 int rem =
width % sl_width;
308 rem =
width % sl_width;
324 const bool skip_blend = (
params->luma == 1.0 &&
params->chroma == 1.0);
331 const size_t stride = 4 * roi_in->
width;
336 const int radius =
params->patch_radius;
337#if defined(CACHE_PIXDIFFS)
338 const size_t scratch_size = (2*radius+3)*(
SLICE_WIDTH + 2*radius + 1);
340 const size_t scratch_size =
SLICE_WIDTH + 2*radius + 1 + 48;
342 size_t padded_scratch_size;
358 for (
int chunk_top = 0 ; chunk_top < roi_out->
height; chunk_top += chk_height)
360 for (
int chunk_left = 0; chunk_left < roi_out->
width; chunk_left += chk_width)
369 float *
const restrict tmpbuf =
dt_get_perthread(scratch_buf, padded_scratch_size);
370 float *
const col_sums = tmpbuf + (radius+1) - chunk_left;
372 const int chunk_bot =
MIN(chunk_top + chk_height, roi_out->
height);
374 const int chunk_right =
MIN(chunk_left + chk_width, roi_out->
width);
376 for (
int i = chunk_top;
i < chunk_bot;
i++)
378 memset(outbuf + 4*(
i*roi_out->
width+chunk_left),
'\0',
sizeof(
float) * 4 * (chunk_right-chunk_left));
381 for (
int p = 0;
p < num_patches;
p++)
387 const int row_min =
MAX(chunk_top,
MAX(0,-patch->
rows));
391 const int row_top =
MAX(row_min,
MAX(radius,radius-patch->
rows));
395 const int scol = patch->
cols;
396 const int col_min =
MAX(chunk_left,-scol);
397 const int col_max =
MIN(chunk_right,roi_out->
width - scol);
400 stride,radius,
params->norm);
401 for (
int row = row_min;
row < row_max;
row++)
404 float distortion = 0.0;
405 for (
int i = col_min - radius;
i <
MIN(col_min+radius, col_max);
i++)
407 distortion += col_sums[
i];
410 const float *in = inbuf + stride *
row;
411 float *
const out = outbuf + (size_t)4 *
width *
row;
413 const float sharpness =
params->sharpness;
414 if (
params->center_weight < 0)
417 for (
int col = col_min; col < col_max; col++)
419 distortion += (col_sums[col+radius] - col_sums[col-radius-1]);
420 const float wt =
gh(distortion * sharpness);
421 const float *
const inpx = in+4*col;
425 out[4*col+c] += pixel[c] * wt;
433 for (
int col = col_min; col < col_max; col++)
435 distortion += (col_sums[col+radius] - col_sums[col-radius-1]);
437 / (1.0f +
params->center_weight);
438 const float wt =
gh(fmaxf(0.0f, dissimilarity * sharpness - 2.0f));
439 const float *
const inpx = in + 4*col;
443 out[4*col+c] += pixel[c] * wt;
448 const int pcol_min = chunk_left -
MIN(radius,
MIN(chunk_left,chunk_left+scol));
449 const int pcol_max = chunk_right +
MIN(radius,
MIN(
width-chunk_right,
width-(chunk_right+scol)));
450 if (
row <
MIN(row_top, row_bot))
453 const float *bot_row = inbuf + (
row+1+radius)*stride;
454 for (
int col = pcol_min; col < pcol_max; col++)
456 const float *
const bot_px = bot_row + 4*col;
460 set_pixdiff(col_sums,radius,
row+radius+1,col,diff);
462 col_sums[col] += diff;
466 else if (
row < row_bot)
468#ifndef CACHE_PIXDIFFS
469 const float *
const top_row = inbuf + (
row-radius)*stride ;
471 const float *
const bot_row = inbuf + (
row+1+radius)*stride ;
473 for (
int col = pcol_min; col < pcol_max; col++)
476 const float *
const bot_px = bot_row + 4*col;
478 col_sums[col] += diff - get_pixdiff(col_sums,radius,
row-radius,col);
480 set_pixdiff(col_sums,radius,
row+1+radius,col,diff);
482 const float *
const top_px = top_row + 4*col;
483 const float *
const bot_px = bot_row + 4*col;
486 col_sums[col] += diff;
491 else if (
row >= row_top &&
row + 1 < row_max)
494#ifndef CACHE_PIXDIFFS
495 const float *top_row = inbuf + (
row-radius)*stride;
497 for (
int col = pcol_min; col < pcol_max; col++)
500 col_sums[col] -= get_pixdiff(col_sums,radius,
row-radius,col);
502 const float *
const top_px = top_row + 4*col;
512 for (
int row = chunk_top;
row < chunk_bot;
row++)
514 float *
const out = outbuf + 4 *
row * roi_out->
width;
515 for (
int col = chunk_left; col < chunk_right; col++)
519 out[4*col+c] /=
out[4*col+3];
527 for (
int row = chunk_top;
row < chunk_bot;
row++)
529 const float *in = inbuf +
row * stride;
531 for (
int col = chunk_left; col < chunk_right; col++)
535 out[4*col+c] = (in[4*col+c] * invert[c]) + (
out[4*col+c] /
out[4*col+3] *
weight[c]);
558 unsigned int current = *
state;
559 unsigned int next = (current >=
max - 1 ? 0 : current + 1);
569 const int horiz_kernel,
const int vert_kernel)
573 .cellsize =
sizeof(float), .overhead = 0,
574 .sizex = 1 << 16, .sizey = 1 };
580 .cellsize =
sizeof(float), .overhead = 0,
581 .sizex = 1, .sizey = 1 << 16 };
604 const int P,
const int q[2],
const int height,
const int width,
605 const int bwidth,
const int hblocksize)
608 const size_t local[3] = { hblocksize, 1, 1 };
623 cl_mem dev_out,
const int q[2],
const int height,
const int width,
624 const size_t sizes[3])
640 cl_mem dev_out,
const dt_iop_roi_t *
const roi_in,
const gboolean profile)
644 const int P =
params->patch_radius;
649 const size_t stride = 4 * roi_in->
width;
656 unsigned int state = 0;
660 if(buckets[
k] == NULL)
goto error;
669 if(err != CL_SUCCESS)
goto error;
675 for(
int p = 0;
p < num_patches;
p++)
685 int q[2] = { patch->
rows, patch->
cols };
701 if(err != CL_SUCCESS)
break;
706 if(err != CL_SUCCESS)
break;
710 const size_t local[3] = { 1, vblocksize, 1 };
711 const float sharpness =
params->sharpness;
712 const float central_pixel_weight =
params->center_weight;
728 if(err != CL_SUCCESS)
break;
732 if(err != CL_SUCCESS)
break;
751 cl_mem dev_in, cl_mem dev_out,
const dt_iop_roi_t *
const roi_in)
759 cl_mem dev_in, cl_mem dev_out,
const dt_iop_roi_t *
const roi_in)
static void error(char *msg)
void dt_atomic_set_int(dt_atomic_int *var, int value)
int dt_atomic_get_int(dt_atomic_int *var)
const dt_colormatrix_t dt_aligned_pixel_t out
int dt_get_num_openmp_threads(void)
Number of OpenMP threads the application decided to use.
static void weight(const float *c1, const float *c2, const float sharpen, dt_aligned_pixel_t weight)
void dt_iop_nap(int32_t usec)
static float kernel(const float *x, const float *y)
static const dt_iop_drawlayer_params_t * params
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...
static float dt_fast_mexp2f(const float x)
static int bucket_next(unsigned int *state, unsigned int max)
static float gh(const float f)
static void init_column_sums(float *const col_sums, const patch_t *const patch, const float *const in, const int row, const int chunk_left, const int chunk_right, const int height, const int width, const int stride, const int radius, const float *const norm)
static float pixel_difference(const float *const pix1, const float *pix2, const dt_aligned_pixel_t norm)
static int nlmeans_cl_run(const dt_nlmeans_param_t *const params, const int devid, cl_mem dev_in, cl_mem dev_out, const dt_iop_roi_t *const roi_in, const gboolean profile)
__DT_CLONE_TARGETS__ int nlmeans_denoise(const float *const inbuf, float *const outbuf, const dt_iop_roi_t *const roi_in, const dt_iop_roi_t *const roi_out, const dt_nlmeans_param_t *const params)
static int compute_slice_height(const int height)
static void get_blocksizes(int *h, int *v, const int radius, const int devid, const int horiz_kernel, const int vert_kernel)
static cl_int nlmeans_cl_accu(const int devid, const int kernel, cl_mem dev_in, cl_mem dev_U4_tt, cl_mem dev_out, const int q[2], const int height, const int width, const size_t sizes[3])
static int scatter(const float scale, const float scattering, const int index1, const int index2)
int nlmeans_denoise_cl(const dt_nlmeans_param_t *const params, const int devid, cl_mem dev_in, cl_mem dev_out, const dt_iop_roi_t *const roi_in)
int nlmeans_denoiseprofile_cl(const dt_nlmeans_param_t *const params, const int devid, cl_mem dev_in, cl_mem dev_out, const dt_iop_roi_t *const roi_in)
#define _mm_prefetch(where, hint)
static struct patch_t * define_patches(const dt_nlmeans_param_t *const params, const int stride, int *num_patches, int *max_shift)
static float compute_center_pixel_norm(const float center_weight, const int radius)
static cl_int nlmeans_cl_horiz(const int devid, const int kernel, cl_mem dev_U4, cl_mem dev_U4_t, const int P, const int q[2], const int height, const int width, const int bwidth, const int hblocksize)
static int compute_slice_width(const int width)
static float diff_of_pixels_diff(const float *const pix1, const float *pix2, const float *const pix3, const float *pix4, const dt_aligned_pixel_t norm)
static cl_int nlmeans_cl_init(const int devid, const int kernel, cl_mem dev_out, const int height, const int width)
int dt_opencl_local_buffer_opt(const int devid, const int kernel, dt_opencl_local_buffer_t *factors)
int dt_opencl_enqueue_kernel_2d(const int dev, const int kernel, const size_t *sizes)
void * dt_opencl_alloc_device_buffer(const int devid, const size_t size)
int dt_opencl_micro_nap(const int devid)
int dt_opencl_set_kernel_arg(const int dev, const int kernel, const int num, const size_t size, const void *arg)
gboolean dt_opencl_finish(const int devid)
int dt_opencl_enqueue_kernel_2d_with_local(const int dev, const int kernel, const size_t *sizes, const size_t *local)
void dt_opencl_release_mem_object(cl_mem mem)
#define DT_OPENCL_DEFAULT_ERROR
#define __OMP_PARALLEL_FOR__(...)
#define dt_pixelpipe_cache_alloc_align_cache(size, id)
#define dt_pixelpipe_cache_free_align(mem)
#define dt_get_perthread(buf, padsize)
#define dt_pixelpipe_cache_alloc_perthread_float(n, padded_size)
static gboolean dt_dev_pixelpipe_has_shutdown(const dt_dev_pixelpipe_t *pipe)
DT_ALIGNED_PIXEL float dt_aligned_pixel_t[4]
#define for_each_channel(_var,...)
static const dt_aligned_pixel_simd_t sign
#define for_four_channels(_var,...)
const float uint32_t state[4]
Region of interest passed through the pixelpipe.
#define __DT_CLONE_TARGETS__