forked from enlightenment/efl
249 lines
6.6 KiB
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;
|
|
}
|
|
}
|
|
}
|