40#if defined(__x86_64__) || defined(__i386__)
41#define DT_PREFETCH(addr) _mm_prefetch(addr, _MM_HINT_T2)
42#define PREFETCH_NTA(addr) _mm_prefetch(addr, _MM_HINT_NTA)
43#elif defined(__GNUC__) && __GNUC__ > 7
44#define DT_PREFETCH(addr) __builtin_prefetch(addr,1,1)
45#define PREFETCH_NTA(addr) __builtin_prefetch(addr,1,0)
47#define DT_PREFETCH(addr)
48#define PREFETCH_NTA(addr)
53 float *
const restrict scanlines,
const size_t padded_size)
56 for(
int y = 0; y <
height; y++)
60 const size_t index = (size_t)y *
width;
70 for (
x = 0; (
x <= radius) && ((
x + radius) <
width);
x++)
72 const int np =
x + radius;
78 scanline[
x] =
L / hits;
84 scanline[
x] =
L / hits;
89 const int op =
x - radius - 1;
90 const int np =
x + radius;
93 scanline[
x] =
L / hits;
98 const int op =
x - radius - 1;
101 scanline[
x] =
L / hits;
105 buf[index +
x] = scanline[
x];
112 float *
const restrict scanlines,
const size_t padded_size)
115 for(
int y = 0; y <
height; y++)
118 float L1 = 0.0f, L2 = 0.0f;
120 const size_t index = (size_t)2 * y *
width;
125 L1 += buf[index + 2*
x];
126 L2 += buf[index + 2*
x + 1];
130 for (
x = 0; (
x <= radius) && ((
x + radius) <
width);
x++)
132 const int np =
x + radius;
136 L1 += buf[index + 2*np];
137 L2 += buf[index + 2*np + 1];
139 scanline[2*
x] = L1 / hits;
140 scanline[2*
x+1] = L2 / hits;
144 for(;
x <= radius &&
x <
width;
x++)
146 scanline[2*
x] = L1 / hits;
147 scanline[2*
x+1] = L2 / hits;
152 const int op =
x - radius - 1;
153 const int np =
x + radius;
154 L1 = L1 - buf[index + 2*op] + buf[index + 2*np];
155 L2 = L2 - buf[index + 2*op + 1] + buf[index + 2*np + 1];
156 scanline[2*
x] = L1 / hits;
157 scanline[2*
x+1] = L2 / hits;
162 const int op =
x - radius - 1;
164 L1 -= buf[index + 2*op];
165 L2 -= buf[index + 2*op + 1];
166 scanline[2*
x] = L1 / hits;
167 scanline[2*
x+1] = L2 / hits;
172 buf[index +
x] = scanline[
x];
185 const float v = values[c];
201 const float *
const restrict values,
float *
const restrict comp)
208 const float t1 =
v - comp[
c];
209 const float t2 = accum[
c] + t1;
210 comp[
c] = (t2 - accum[
c]) - t1;
216 float *
const restrict comp)
221 const float t1 = -
values[
c] - comp[
c];
222 const float t2 = accum[
c] + t1;
223 comp[
c] = (t2 - accum[
c]) - t1;
231 out[
c] = in[
c] / scale;
235static void sub_16wide(
float *
const restrict accum,
const float *
const restrict values)
238 for(
size_t c = 0; c < 16; c++)
239 accum[c] -= values[c];
244static void load_add_16wide(
float *
const restrict
out,
float *
const restrict accum,
const float *
const restrict in)
247 for (
size_t c = 0; c < 16; c++)
249 const float v = in[c];
256static void sub_16wide_Kahan(
float *
const restrict accum,
const float *
const restrict values,
257 float *
const restrict comp)
259 __OMP_SIMD__(aligned(accum,comp : 64) aligned(values : 16))
260 for(
size_t c = 0; c < 16; c++)
262 const float v = -values[c];
264 const float t1 =
v - comp[c];
265 const float t2 = accum[c] + t1;
266 comp[c] = (t2 - accum[c]) - t1;
274 const float *
const restrict in,
float *
const restrict comp)
277 for (
size_t c = 0; c < 16; c++)
279 const float v = in[c];
282 const float t1 =
v - comp[c];
283 const float t2 = accum[c] + t1;
284 comp[c] = (t2 - accum[c]) - t1;
294 for (
size_t c = 0; c < 16; c++)
302 for(
size_t c = 0; c < 16; c++)
303 out[c] = in[c] / scale;
307static void sub_Nwide_Kahan(
const size_t N,
float *
const restrict accum,
const float *
const restrict values,
308 float *
const restrict comp)
311 for(
size_t c = 0; c <
N; c++)
313 const float v = -values[c];
315 const float t1 =
v - comp[c];
316 const float t2 = accum[c] + t1;
317 comp[c] = (t2 - accum[c]) - t1;
325 const float *
const restrict in,
float *
const restrict comp)
328 for (
size_t c = 0; c <
N; c++)
330 const float v = in[c];
333 const float t1 =
v - comp[c];
334 const float t2 = accum[c] + t1;
335 comp[c] = (t2 - accum[c]) - t1;
345 for(
size_t c = 0; c <
N; c++)
346 out[c] = in[c] / scale;
352 float *
const restrict scanlines,
const size_t padded_size)
355 for(
int y = 0; y <
height; y++)
360 const size_t index = (size_t)4 * y *
width;
361 float *
const restrict bufp = buf + index;
366 load_add_4wide(scratch + 4*
x,
L, bufp + 4*
x);
370 for (
x = 0; (
x <= radius) && ((
x + radius) <
width);
x++)
372 const int np =
x + radius;
374 load_add_4wide(scratch + 4*np,
L, bufp + 4*np);
375 store_scaled_4wide(bufp + 4*
x,
L, hits);
379 for(;
x <= radius &&
x <
width;
x++)
381 store_scaled_4wide(bufp + 4*
x,
L, hits);
388 const int op =
x - radius - 1;
389 const int np =
x + radius;
390 sub_4wide(
L, scratch + 4*op);
391 load_add_4wide(scratch + 4*np,
L, bufp + 4*np);
392 store_scaled_4wide(bufp + 4*
x,
L, hits);
397 const int op =
x - radius - 1;
399 sub_4wide(
L, scratch + 4*op);
400 store_scaled_4wide(bufp + 4*
x,
L, hits);
409 const size_t radius,
float *
const restrict scratch)
418 load_add_4wide_Kahan(scratch + 4*
x,
L, buf + 4*
x, comp);
422 for (
x = 0; (
x <= radius) && ((
x + radius) <
width);
x++)
424 const int np =
x + radius;
426 load_add_4wide_Kahan(scratch + 4*np,
L, buf + 4*np, comp);
427 store_scaled_4wide(buf + 4*
x,
L, hits);
431 for(;
x <= radius &&
x <
width;
x++)
433 store_scaled_4wide(buf + 4*
x,
L, hits);
438 const int op =
x - radius - 1;
439 const int np =
x + radius;
440 sub_4wide_Kahan(
L, scratch + 4*op, comp);
441 load_add_4wide_Kahan(scratch + 4*np,
L, buf + 4*np, comp);
442 store_scaled_4wide(buf + 4*
x,
L, hits);
447 const int op =
x - radius - 1;
449 sub_4wide_Kahan(
L, scratch + 4*op, comp);
450 store_scaled_4wide(buf + 4*
x,
L, hits);
458 const size_t radius,
float *
const restrict scratch)
474 for (
x = 0; (
x <= radius) && ((
x + radius) <
width);
x++)
476 const int np =
x + radius;
483 for(;
x <= radius &&
x <
width;
x++)
490 const int op =
x - radius - 1;
491 const int np =
x + radius;
499 const int op =
x - radius - 1;
510 const size_t radius,
float *
const restrict scratch)
518 for(
size_t r = (2*radius+1);
r > 1 ;
r >>= 1) mask = (mask << 1) | 1;
523 for (
size_t y = 0; y <
MIN(radius,
height); y++)
527 const float v = buf[y*
width];
533 for (y = 0; y <= radius && y + radius <
height; y++)
536 const int np = y + radius;
539 const float v = buf[np*
width];
541 scratch[np&mask] =
v;
546 for(; y <= radius && y <
height; y++)
551 for( ; y + radius <
height; y++)
553 const int np = y + radius;
554 const int op = y - radius - 1;
556 L -= scratch[op&mask];
557 const float v = buf[np*
width];
559 scratch[np&mask] =
v;
566 const int op = y - radius - 1;
568 L -= scratch[op&mask];
578 const size_t radius,
float *
const restrict scratch)
586 for(
size_t r = (2*radius+1);
r > 1 ;
r >>= 1) mask = (mask << 1) | 1;
592 for (
size_t y = 0; y <
MIN(radius,
height); y++)
596 const float v = buf[y*
width];
602 for (y = 0; y <= radius && y + radius <
height; y++)
605 const int np = y + radius;
608 const float v = buf[np*
width];
610 scratch[np&mask] =
v;
615 for(; y <= radius && y <
height; y++)
620 for( ; y + radius <
height; y++)
622 const int np = y + radius;
623 const int op = y - radius - 1;
626 const float v = buf[np*
width];
628 scratch[np&mask] =
v;
635 const int op = y - radius - 1;
647 float *
const restrict scratch)
655 for(
size_t r = (2*radius+1);
r > 1 ;
r >>= 1) mask = (mask << 1) | 1;
660 for (
size_t y = 0; y <
MIN(radius,
height); y++)
664 load_add_4wide(scratch + 4*(y&mask),
L, buf + y *
width);
668 for (y = 0; y <= radius && y + radius <
height; y++)
671 const int np = y + radius;
674 load_add_4wide(scratch + 4*(np&mask),
L, buf + np*
width);
675 store_scaled_4wide(buf + y*
width,
L, hits);
679 for(; y <= radius && y <
height; y++)
681 store_scaled_4wide(buf + y*
width,
L, hits);
684 for ( ; y + radius <
height; y++)
686 const int np = y + radius;
687 const int op = y - radius - 1;
689 sub_4wide(
L, scratch + 4*(op&mask));
690 load_add_4wide(scratch + 4*(np&mask),
L, buf + np*
width);
691 store_scaled_4wide(buf + y*
width,
L, hits);
696 const int op = y - radius - 1;
698 sub_4wide(
L, scratch + 4*(op&mask));
699 store_scaled_4wide(buf + y*
width,
L, hits);
707 const size_t radius,
float *
const restrict scratch)
715 for(
size_t r = (2*radius+1);
r > 1 ;
r >>= 1) mask = (mask << 1) | 1;
721 for (
size_t y = 0; y <
MIN(radius,
height); y++)
725 load_add_4wide_Kahan(scratch + 4*(y&mask),
L, buf + y *
width, comp);
729 for (y = 0; y <= radius && y + radius <
height; y++)
732 const int np = y + radius;
735 load_add_4wide_Kahan(scratch + 4*(np&mask),
L, buf + np*
width, comp);
736 store_scaled_4wide(buf + y*
width,
L, hits);
740 for(; y <= radius && y <
height; y++)
742 store_scaled_4wide(buf + y*
width,
L, hits);
745 for ( ; y + radius <
height; y++)
747 const int np = y + radius;
748 const int op = y - radius - 1;
750 sub_4wide_Kahan(
L, scratch + 4*(op&mask), comp);
751 load_add_4wide_Kahan(scratch + 4*(np&mask),
L, buf + np*
width, comp);
752 store_scaled_4wide(buf + y*
width,
L, hits);
757 const int op = y - radius - 1;
759 sub_4wide_Kahan(
L, scratch + 4*(op&mask), comp);
760 store_scaled_4wide(buf + y*
width,
L, hits);
768 const size_t radius,
float *
const restrict scratch)
776 for(
size_t r = (2*radius+1);
r > 1 ;
r >>= 1) mask = (mask << 1) | 1;
781 for (
size_t y = 0; y <
MIN(radius,
height); y++)
789 for (y = 0; y <= radius && y + radius <
height; y++)
792 const int np = y + radius;
800 for(; y <= radius && y <
height; y++)
805 for ( ; y + radius <
height; y++)
807 const int np = y + radius;
808 const int op = y - radius - 1;
818 const int op = y - radius - 1;
830 const size_t radius,
float *
const restrict scratch)
838 for(
size_t r = (2*radius+1);
r > 1 ;
r >>= 1) mask = (mask << 1) | 1;
844 for (
size_t y = 0; y <
MIN(radius,
height); y++)
852 for (y = 0; y <= radius && y + radius <
height; y++)
855 const int np = y + radius;
863 for(; y <= radius && y <
height; y++)
868 for ( ; y + radius <
height; y++)
870 const int np = y + radius;
871 const int op = y - radius - 1;
881 const int op = y - radius - 1;
892 float *
const restrict scanlines,
const size_t padded_size)
906 for( ; col < (
width & ~3); col += 4)
908 for( ; col <
width; col++)
920 size_t eff_height = 2;
921 for(
size_t r = (2*radius+1);
r > 1 ;
r >>= 1) eff_height <<= 1;
928 const unsigned iterations)
939 for(
unsigned iteration = 0; iteration < iterations; iteration++)
951 const unsigned iterations)
962 for(
unsigned iteration = 0; iteration < iterations; iteration++)
981 for (
size_t col = 0; col <
width; col += 16)
984 if (col + 16 <=
width)
992 for( ; col_ < (
width & ~3); col_ += 4)
994 for( ; col_ <
width; col_++)
1005 const unsigned iterations)
1008 for(
unsigned iteration = 0; iteration < iterations; iteration++)
1029 const int radius,
const unsigned iterations)
1036 const size_t Ndim =
MAX(4*
width,16*eff_height);
1041 for (
unsigned iteration = 0; iteration < iterations; iteration++)
1051 const int radius,
const unsigned iterations)
1075 float *
const restrict user_scratch)
1079 float *
const restrict scratch = user_scratch ? user_scratch
1090 float *
const restrict scratch = user_scratch ? user_scratch
1108 size_t channels =
ch & ~BOXFILTER_KAHAN_SUM;
1118 float m = -(FLT_MAX);
1120 for(
int j = 0; j <
n; j++)
1127static inline void box_max_1d(
int N,
const float *
const restrict
x,
float *
const restrict y,
size_t stride_y,
int w)
1130 for(
int i = 0;
i <
N;
i++)
1133 y[
i * stride_y] =
m;
1136 if(
i - w >= 0 &&
x[
i - w] ==
m)
1138 const int start =
i - w + 1;
1151 for (
size_t c = 0; c < 16; c++)
1158 for (
size_t c = 0; c < 16; c++)
1160 m[c] = fmaxf(
m[c], base[c]);
1167 for (
size_t c = 0; c < 16; c++)
1169 const float v = base[c];
1171 m[c] = fmaxf(
m[c],
v);
1179 const int stride,
const int w,
const size_t mask)
1181 float DT_ALIGNED_ARRAY m[16] = { -(FLT_MAX), -(FLT_MAX), -(FLT_MAX), -(FLT_MAX),
1182 -(FLT_MAX), -(FLT_MAX), -(FLT_MAX), -(FLT_MAX),
1183 -(FLT_MAX), -(FLT_MAX), -(FLT_MAX), -(FLT_MAX),
1184 -(FLT_MAX), -(FLT_MAX), -(FLT_MAX), -(FLT_MAX) };
1185 for(
size_t i = 0;
i <
MIN(w + 1,
N);
i++)
1190 for(
size_t i = 0;
i <
N;
i++)
1200 for(
int j =
i - w + 1; j <
MIN(
i + w + 1,
N); j++)
1206 const size_t n =
i + w + 1;
1227 float *
const restrict scratch =
dt_get_perthread(scratch_buffers,allocsize);
1232 for(
int col = 0; col < (
width & ~15); col += 16)
1234 float *
const restrict scratch =
dt_get_perthread(scratch_buffers,allocsize);
1238 for (
size_t col =
width & ~15 ; col <
width; col++)
1240 float *
const restrict scratch = scratch_buffers;
1265 for(
int j = 0; j <
n; j++)
1272static inline void box_min_1d(
int N,
const float *
x,
float *y,
size_t stride_y,
int w)
1275 for(
int i = 0;
i <
N;
i++)
1277 y[
i * stride_y] =
m;
1278 if(
i - w >= 0 &&
x[
i - w] ==
m)
1280 const int start = (
i - w + 1);
1292 for (
size_t c = 0; c < 16; c++)
1294 m[c] = fminf(
m[c], base[c]);
1301 for (
size_t c = 0; c < 16; c++)
1303 const float v = base[c];
1305 m[c] = fminf(
m[c],
v);
1313 const int stride,
const int w,
const size_t mask)
1316 FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX,
1317 FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX,
1318 FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX };
1319 for(
size_t i = 0;
i <
MIN(w + 1,
N);
i++)
1324 for(
size_t i = 0;
i <
N;
i++)
1334 for(
int j =
i - w + 1; j <
MIN(
i + w + 1,
N); j++)
1340 const size_t n =
i + w + 1;
1362 float *
const restrict scratch =
dt_get_perthread(scratch_buffers,allocsize);
1367 for(
size_t col = 0; col < (
width & ~15); col += 16)
1369 float *
const restrict scratch =
dt_get_perthread(scratch_buffers,allocsize);
1373 for (
size_t col =
width & ~15 ; col <
width; col++)
1375 float *
const restrict scratch = scratch_buffers;
static __DT_CLONE_TARGETS__ void blur_vertical_16wide(float *const restrict buf, const size_t height, const size_t width, const size_t radius, float *const restrict scratch)
static __DT_CLONE_TARGETS__ void set_16wide(float *const restrict out, const float value)
static void update_max_16wide(float m[16], const float *const restrict base)
static __DT_CLONE_TARGETS__ void blur_vertical_1wide(float *const restrict buf, const size_t height, const size_t width, const size_t radius, float *const restrict scratch)
static void load_update_max_16wide(float *const restrict out, float m[16], const float *const restrict base)
#define PREFETCH_NTA(addr)
static void update_min_16wide(float m[16], const float *const restrict base)
static float window_max(const float *x, int n)
static int box_mean_2ch(float *const restrict in, const size_t height, const size_t width, const int radius, const unsigned iterations)
static __DT_CLONE_TARGETS__ int box_max_1ch(float *const buf, const size_t height, const size_t width, const unsigned w)
static __DT_CLONE_TARGETS__ void blur_vertical_16wide_Kahan(float *const restrict buf, const size_t height, const size_t width, const size_t radius, float *const restrict scratch)
static __DT_CLONE_TARGETS__ void sub_16wide_Kahan(float *const restrict accum, const float *const restrict values, float *const restrict comp)
int dt_box_max(float *const buf, const size_t height, const size_t width, const int ch, const int radius)
static __DT_CLONE_TARGETS__ void blur_vertical_1ch(float *const restrict buf, const size_t height, const size_t width, const size_t radius, float *const restrict scanlines, const size_t padded_size)
static __DT_CLONE_TARGETS__ int dt_box_mean_4ch_Kahan(float *const buf, const size_t height, const size_t width, const int radius, const unsigned iterations)
static __DT_CLONE_TARGETS__ void blur_horizontal_4ch(float *const restrict buf, const size_t height, const size_t width, const size_t radius, float *const restrict scanlines, const size_t padded_size)
static __DT_CLONE_TARGETS__ void blur_vertical_4wide_Kahan(float *const restrict buf, const size_t height, const size_t width, const size_t radius, float *const restrict scratch)
static __DT_CLONE_TARGETS__ void blur_horizontal_1ch(float *const restrict buf, const int height, const int width, const int radius, float *const restrict scanlines, const size_t padded_size)
static __DT_CLONE_TARGETS__ void blur_horizontal_2ch(float *const restrict buf, const int height, const int width, const int radius, float *const restrict scanlines, const size_t padded_size)
static float window_min(const float *x, int n)
static __DT_CLONE_TARGETS__ int dt_box_mean_1ch(float *const buf, const size_t height, const size_t width, const size_t radius, const unsigned iterations)
static __DT_CLONE_TARGETS__ int dt_box_mean_4ch(float *const buf, const int height, const int width, const int radius, const unsigned iterations)
#define DT_PREFETCH(addr)
static __DT_CLONE_TARGETS__ void blur_vertical_4wide(float *const restrict buf, const size_t height, const size_t width, const size_t radius, float *const restrict scratch)
static __DT_CLONE_TARGETS__ void store_scaled_Nwide(const size_t N, float *const restrict out, const float *const restrict in, const float scale)
static __DT_CLONE_TARGETS__ void sub_Nwide_Kahan(const size_t N, float *const restrict accum, const float *const restrict values, float *const restrict comp)
static __DT_CLONE_TARGETS__ void sub_16wide(float *const restrict accum, const float *const restrict values)
static __DT_CLONE_TARGETS__ void store_16wide(float *const restrict out, const float *const restrict in)
static __DT_CLONE_TARGETS__ int box_mean_vert_1ch_Kahan(float *const buf, const int height, const size_t width, const size_t radius)
int dt_box_mean_horizontal(float *const restrict buf, const size_t width, const int ch, const int radius, float *const restrict user_scratch)
static __DT_CLONE_TARGETS__ void blur_vertical_1wide_Kahan(float *const restrict buf, const size_t height, const size_t width, const size_t radius, float *const restrict scratch)
int dt_box_mean(float *const buf, const size_t height, const size_t width, const int ch, const int radius, const unsigned iterations)
static void box_max_1d(int N, const float *const restrict x, float *const restrict y, size_t stride_y, int w)
static __DT_CLONE_TARGETS__ int box_min_1ch(float *const buf, const size_t height, const size_t width, const int w)
int dt_box_mean_vertical(float *const buf, const size_t height, const size_t width, const int ch, const int radius)
static __DT_CLONE_TARGETS__ void store_scaled_16wide(float *const restrict out, const float *const restrict in, const float scale)
static void load_update_min_16wide(float *const restrict out, float m[16], const float *const restrict base)
static __DT_CLONE_TARGETS__ void blur_horizontal_4ch_Kahan(float *const restrict buf, const size_t width, const size_t radius, float *const restrict scratch)
static __DT_CLONE_TARGETS__ void blur_horizontal_Nch_Kahan(const size_t N, float *const restrict buf, const size_t width, const size_t radius, float *const restrict scratch)
static void box_min_vert_16wide(const int N, float *const restrict scratch, float *const restrict buf, const int stride, const int w, const size_t mask)
static __DT_CLONE_TARGETS__ void load_add_Nwide_Kahan(const size_t N, float *const restrict out, float *const restrict accum, const float *const restrict in, float *const restrict comp)
static void box_max_vert_16wide(const int N, float *const restrict scratch, float *const restrict buf, const int stride, const int w, const size_t mask)
static __DT_CLONE_TARGETS__ void load_add_16wide(float *const restrict out, float *const restrict accum, const float *const restrict in)
static __DT_CLONE_TARGETS__ size_t _compute_effective_height(const size_t height, const size_t radius)
int dt_box_min(float *const buf, const size_t height, const size_t width, const int ch, const int radius)
static __DT_CLONE_TARGETS__ void load_add_16wide_Kahan(float *const restrict out, float *const restrict accum, const float *const restrict in, float *const restrict comp)
static void box_min_1d(int N, const float *x, float *y, size_t stride_y, int w)
#define BOXFILTER_KAHAN_SUM
static const float const float const float min
const dt_colormatrix_t dt_aligned_pixel_t out
float *const restrict const size_t const size_t ch
#define dt_unreachable_codepath()
Mark a branch as impossible.
#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 Kahan_sum(const float m, float *const __restrict__ c, const float add)
#define DT_ALIGNED_ARRAY
Align an object on a cacheline boundary, so AVX2 can load it whole.
#define __OMP_SIMD__(...)
#define __OMP_PARALLEL_FOR__(...)
#define dt_pixelpipe_cache_alloc_align_float_cache(pixels, id)
#define dt_pixelpipe_cache_free_align(mem)
#define dt_get_perthread(buf, padsize)
#define dt_pixelpipe_cache_alloc_perthread_float(n, padded_size)
DT_ALIGNED_PIXEL float dt_aligned_pixel_t[4]
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...
#define for_four_channels(_var,...)
static const dt_aligned_pixel_simd_t value
#define __DT_CLONE_TARGETS__