efl/src/lib/evas/filters/blur/blur_box_alpha_.c

249 lines
6.6 KiB
C

/* @file blur_box_alpha_.c
* Defines the following functions:
* _box_blur_alpha_horiz_step
* _box_blur_alpha_vert_step
*/
#include "../evas_filter_private.h"
static inline void
_box_blur_alpha_horiz_step(const DATA8* restrict const srcdata,
DATA8* restrict const dstdata,
const int* restrict const radii,
const int len,
const int loops)
{
const DATA8* restrict src;
DATA8* restrict dst;
DATA8* restrict span1;
DATA8* restrict span2;
#if DIV_USING_BITSHIFT
int pow2_shifts[6] = {0};
int numerators[6] = {0};
for (int run = 0; radii[run]; run++)
{
const int div = radii[run] * 2 + 1;
pow2_shifts[run] = evas_filter_smallest_pow2_larger_than(div << 10);
numerators[run] = (1 << pow2_shifts[run]) / (div);
}
#endif
span1 = alloca(len);
span2 = alloca(len);
memset(span1, 0, len);
memset(span2, 0, len);
// For each line, apply as many blurs as requested
for (int l = 0; l < loops; l++)
{
int run;
// New line: reset source & destination pointers
src = srcdata + len * l;
if (!radii[1]) // Only one run
dst = dstdata + len * l;
else
dst = span1;
// Apply blur with current radius
for (run = 0; radii[run]; run++)
{
const int radius = radii[run];
const int left = MIN(radius, len);
#if DIV_USING_BITSHIFT
const int pow2 = pow2_shifts[run];
const int numerator = numerators[run];
#else
const int divider = 2 * radius + 1;
#endif
const DATA8* restrict sl = src;
const DATA8* restrict sr = src;
const DATA8* restrict sre = src + len;
const DATA8* restrict sle = src + len - radius;
DATA8* restrict d = dst;
int acc = 0, count = 0;
// Read-ahead & accumulate
for (int x = left; x > 0; x--)
{
acc += *sr++;
count++;
}
// Left edge
for (int x = left; x > 0; x--)
{
if (sr < sre)
{
acc += *sr++;
count++;
}
*d++ = acc / count;
}
// Middle part, normal blur
while (sr < sre)
{
acc += *sr++;
*d++ = DIVIDE(acc);
acc -= *sl++;
}
// Right edge
count = 2 * radius + 1;
while (sl < sle)
{
*d++ = acc / (--count);
acc -= *sl++;
}
// More runs to go: swap spans
if (radii[run + 1])
{
src = dst;
if (radii[run + 2])
{
// Two more runs: swap
DATA8* swap = span1;
span1 = span2;
span2 = swap;
dst = span1;
}
else
{
// Last run: write directly to dstdata
dst = dstdata + len * l;
}
}
}
}
}
// ATTENTION: Make sure the below code's inner loop is the SAME as above.
static inline void
_box_blur_alpha_vert_step(const DATA8* restrict const srcdata,
DATA8* restrict const dstdata,
const int* restrict const radii,
const int len,
const int loops)
{
/* Note: This function tries to optimize cache hits by working on
* contiguous horizontal spans.
*/
const int step = loops;
DATA8* restrict src;
DATA8* restrict dst;
DATA8* restrict span1;
DATA8* restrict span2;
#if DIV_USING_BITSHIFT
int pow2_shifts[6] = {0};
int numerators[6] = {0};
for (int run = 0; radii[run]; run++)
{
const int div = radii[run] * 2 + 1;
pow2_shifts[run] = evas_filter_smallest_pow2_larger_than(div << 10);
numerators[run] = (1 << pow2_shifts[run]) / (div);
}
#endif
span1 = alloca(len);
span2 = alloca(len);
// For each line, apply as many blurs as requested
for (int l = 0; l < loops; l++)
{
int run;
// Rotate input into work span
const DATA8* srcptr = srcdata + l;
DATA8* s = span1;
for (int k = len; k; --k)
{
*s++ = *srcptr;
srcptr += step;
}
src = span1;
dst = span2;
// Apply blur with current radius
for (run = 0; radii[run]; run++)
{
const int radius = radii[run];
const int left = MIN(radius, len);
#if DIV_USING_BITSHIFT
const int pow2 = pow2_shifts[run];
const int numerator = numerators[run];
#else
const int divider = 2 * radius + 1;
#endif
const DATA8* restrict sl = src;
const DATA8* restrict sr = src;
const DATA8* restrict sre = src + len;
const DATA8* restrict sle = src + len - radius;
DATA8* restrict d = dst;
int acc = 0, count = 0;
// Read-ahead & accumulate
for (int x = left; x > 0; x--)
{
acc += *sr++;
count++;
}
// Left edge
for (int x = left; x > 0; x--)
{
if (sr < sre)
{
acc += *sr++;
count++;
}
*d++ = acc / count;
}
// Middle part, normal blur
while (sr < sre)
{
acc += *sr++;
*d++ = DIVIDE(acc);
acc -= *sl++;
}
// Right edge
count = 2 * radius + 1;
while (sl < sle)
{
*d++ = acc / (--count);
acc -= *sl++;
}
// More runs to go: swap spans
if (radii[run + 1])
{
DATA8* swap = src;
src = dst;
dst = swap;
}
}
// Last run: rotate & copy back to destination
DATA8* restrict dstptr = dstdata + l;
for (int k = len; k; --k)
{
*dstptr = *dst++;
dstptr += step;
}
}
}