Evas filters: Add basic optimization for RGBA gaussian blur

This commit is contained in:
Jean-Philippe Andre 2014-03-11 12:10:42 +09:00
parent cb69700389
commit 9c3a3373b3
3 changed files with 119 additions and 96 deletions

View File

@ -1,3 +1,9 @@
/* @file blur_gaussian_alpha_.c
* Should define the functions:
* - _gaussian_blur_horiz_alpha_step
* - _gaussian_blur_vert_alpha_step
*/
/* Datatypes and MIN macro */
#include "evas_common_private.h"
#include "../evas_filter_private.h"

View File

@ -0,0 +1,99 @@
/* @file blur_gaussian_rgba_.c
* Should define the functions:
* - _gaussian_blur_horiz_rgba_step
* - _gaussian_blur_vert_rgba_step
*/
#include "evas_common_private.h"
#include "../evas_filter_private.h"
#if !defined (FUNCTION_NAME) || !defined (STEP)
# error Must define FUNCTION_NAME and STEP
#endif
static inline void
FUNCTION_NAME(const DATA32* restrict srcdata, DATA32* restrict dstdata,
const int radius, const int len,
const int loops, const int loopstep,
const int* restrict weights, const int pow2_divider)
{
const int diameter = 2 * radius + 1;
const int left = MIN(radius, len);
const int right = MIN(radius, (len - radius));
const DATA32* restrict src;
DATA32* restrict dst;
int i, j, k;
for (i = loops; i; --i)
{
src = srcdata;
dst = dstdata;
// left
for (k = 0; k < left; k++, dst += STEP)
{
int acc[4] = {0};
int divider = 0;
const DATA32* restrict s = src;
for (j = 0; j <= k + radius; j++, s += STEP)
{
const int weightidx = j + radius - k;
acc[ALPHA] += A_VAL(s) * weights[weightidx];
acc[RED] += R_VAL(s) * weights[weightidx];
acc[GREEN] += G_VAL(s) * weights[weightidx];
acc[BLUE] += B_VAL(s) * weights[weightidx];
divider += weights[weightidx];
}
//if (!divider) abort();
A_VAL(dst) = acc[ALPHA] / divider;
R_VAL(dst) = acc[RED] / divider;
G_VAL(dst) = acc[GREEN] / divider;
B_VAL(dst) = acc[BLUE] / divider;
}
// middle
for (k = len - (2 * radius); k > 0; k--, src += STEP, dst += STEP)
{
int acc[4] = {0};
const DATA32* restrict s = src;
for (j = 0; j < diameter; j++, s += STEP)
{
acc[ALPHA] += A_VAL(s) * weights[j];
acc[RED] += R_VAL(s) * weights[j];
acc[GREEN] += G_VAL(s) * weights[j];
acc[BLUE] += B_VAL(s) * weights[j];
}
A_VAL(dst) = acc[ALPHA] >> pow2_divider;
R_VAL(dst) = acc[RED] >> pow2_divider;
G_VAL(dst) = acc[GREEN] >> pow2_divider;
B_VAL(dst) = acc[BLUE] >> pow2_divider;
}
// right
for (k = 0; k < right; k++, dst += STEP, src += STEP)
{
int acc[4] = {0};
int divider = 0;
const DATA32* restrict s = src;
for (j = 0; j < 2 * radius - k; j++, s += STEP)
{
acc[ALPHA] += A_VAL(s) * weights[j];
acc[RED] += R_VAL(s) * weights[j];
acc[GREEN] += G_VAL(s) * weights[j];
acc[BLUE] += B_VAL(s) * weights[j];
divider += weights[j];
}
//if (!divider) abort();
A_VAL(dst) = acc[ALPHA] / divider;
R_VAL(dst) = acc[RED] / divider;
G_VAL(dst) = acc[GREEN] / divider;
B_VAL(dst) = acc[BLUE] / divider;
}
dstdata += loopstep;
srcdata += loopstep;
}
}
#undef FUNCTION_NAME
#undef STEP

View File

@ -5,7 +5,7 @@
#include <time.h>
// Enable debug if you're working on optimizations
#define DEBUG_TIME 0
#define DEBUG_TIME 1
// Windows build will break if CLOCK_MONOTONIC is used
#if !defined(_POSIX_MONOTONIC_CLOCK) || (_POSIX_MONOTONIC_CLOCK < 0)
@ -379,82 +379,6 @@ _sin_blur_weights_get(int *weights, int *pow2_divider, int radius)
*pow2_divider = nextpow2;
}
static void
_gaussian_blur_step_rgba(DATA32 *src, DATA32 *dst, int radius, int len, int step,
int *weights, int pow2_divider)
{
const int diameter = 2 * radius + 1;
int left = MIN(radius, len);
int right = MIN(radius, (len - radius));
int j, k;
// left
for (k = 0; k < left; k++, dst += step)
{
int acc[4] = {0};
int divider = 0;
DATA32 *s = src;
for (j = 0; j <= k + radius; j++, s += step)
{
const int weightidx = j + radius - k;
acc[ALPHA] += A_VAL(s) * weights[weightidx];
acc[RED] += R_VAL(s) * weights[weightidx];
acc[GREEN] += G_VAL(s) * weights[weightidx];
acc[BLUE] += B_VAL(s) * weights[weightidx];
divider += weights[weightidx];
}
if (!divider) goto div_zero;
A_VAL(dst) = acc[ALPHA] / divider;
R_VAL(dst) = acc[RED] / divider;
G_VAL(dst) = acc[GREEN] / divider;
B_VAL(dst) = acc[BLUE] / divider;
}
// middle
for (k = len - (2 * radius); k > 0; k--, src += step, dst += step)
{
int acc[4] = {0};
DATA32 *s = src;
for (j = 0; j < diameter; j++, s += step)
{
acc[ALPHA] += A_VAL(s) * weights[j];
acc[RED] += R_VAL(s) * weights[j];
acc[GREEN] += G_VAL(s) * weights[j];
acc[BLUE] += B_VAL(s) * weights[j];
}
A_VAL(dst) = acc[ALPHA] >> pow2_divider;
R_VAL(dst) = acc[RED] >> pow2_divider;
G_VAL(dst) = acc[GREEN] >> pow2_divider;
B_VAL(dst) = acc[BLUE] >> pow2_divider;
}
// right
for (k = 0; k < right; k++, dst += step, src += step)
{
int acc[4] = {0};
int divider = 0;
DATA32 *s = src;
for (j = 0; j < 2 * radius - k; j++, s += step)
{
acc[ALPHA] += A_VAL(s) * weights[j];
acc[RED] += R_VAL(s) * weights[j];
acc[GREEN] += G_VAL(s) * weights[j];
acc[BLUE] += B_VAL(s) * weights[j];
divider += weights[j];
}
if (!divider) goto div_zero;
A_VAL(dst) = acc[ALPHA] / divider;
R_VAL(dst) = acc[RED] / divider;
G_VAL(dst) = acc[GREEN] / divider;
B_VAL(dst) = acc[BLUE] / divider;
}
return;
div_zero:
CRI("Division by zero avoided! Something is very wrong here!");
}
#define FUNCTION_NAME _gaussian_blur_horiz_alpha_step
#define STEP 1
#include "./blur/blur_gaussian_alpha_.c"
@ -473,7 +397,7 @@ _gaussian_blur_horiz_alpha(const DATA8 *src, DATA8 *dst, int radius, int w, int
DEBUG_TIME_END();
}
// w steps, loops = w --> STEP = loops
// Step size is w (row by row), loops = w, so STEP = 'loops'
#define FUNCTION_NAME _gaussian_blur_vert_alpha_step
#define STEP loops
#include "./blur/blur_gaussian_alpha_.c"
@ -492,45 +416,39 @@ _gaussian_blur_vert_alpha(const DATA8 *src, DATA8 *dst, int radius, int w, int h
DEBUG_TIME_END();
}
#define FUNCTION_NAME _gaussian_blur_horiz_rgba_step
#define STEP 1
#include "./blur/blur_gaussian_rgba_.c"
static void
_gaussian_blur_horiz_rgba(DATA32 *src, DATA32 *dst, int radius, int w, int h)
{
int *weights;
int k, pow2_div = 0;
int pow2_div = 0;
weights = alloca((2 * radius + 1) * sizeof(int));
_sin_blur_weights_get(weights, &pow2_div, radius);
DEBUG_TIME_BEGIN();
for (k = h; k; k--)
{
_gaussian_blur_step_rgba(src, dst, radius, w, 1, weights, pow2_div);
dst += w;
src += w;
}
_gaussian_blur_horiz_rgba_step(src, dst, radius, w, h, w, weights, pow2_div);
DEBUG_TIME_END();
}
#define FUNCTION_NAME _gaussian_blur_vert_rgba_step
#define STEP loops
#include "./blur/blur_gaussian_rgba_.c"
static void
_gaussian_blur_vert_rgba(DATA32 *src, DATA32 *dst, int radius, int w, int h)
{
int *weights;
int k, pow2_div = 0;
int pow2_div = 0;
weights = alloca((2 * radius + 1) * sizeof(int));
_sin_blur_weights_get(weights, &pow2_div, radius);
DEBUG_TIME_BEGIN();
for (k = w; k; k--)
{
_gaussian_blur_step_rgba(src, dst, radius, h, w, weights, pow2_div);
dst += 1;
src += 1;
}
_gaussian_blur_vert_rgba_step(src, dst, radius, h, w, 1, weights, pow2_div);
DEBUG_TIME_END();
}