Evas filters: Use box blur by default

BOX blur is a lot faster (and easier to optimize, too)
than GAUSSIAN blur. Repeating 2x or 3x BOX blur will also
give similar results to GAUSSIAN blur (very smooth), but
in much less time.

Add a count parameter to the BOX blur instruction.
This commit is contained in:
Jean-Philippe Andre 2014-03-11 18:21:46 +09:00
parent 4e249143a5
commit 2a1ba1b908
4 changed files with 131 additions and 22 deletions

View File

@ -898,7 +898,7 @@ evas_filter_command_fill_add(Evas_Filter_Context *ctx, void *draw_context,
int
evas_filter_command_blur_add(Evas_Filter_Context *ctx, void *drawctx,
int inbuf, int outbuf, Evas_Filter_Blur_Type type,
int dx, int dy, int ox, int oy)
int dx, int dy, int ox, int oy, int count)
{
Evas_Filter_Command *cmd = NULL;
Evas_Filter_Buffer *in = NULL, *out = NULL, *tmp = NULL, *in_dy = NULL;
@ -911,18 +911,79 @@ evas_filter_command_blur_add(Evas_Filter_Context *ctx, void *drawctx,
EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, -1);
EINA_SAFETY_ON_NULL_RETURN_VAL(drawctx, -1);
if (dx < 0) dx = 0;
if (dy < 0) dy = 0;
if (!dx && !dy) goto fail;
switch (type)
{
case EVAS_FILTER_BLUR_BOX:
if (dx < 0) dx = 0;
if (dy < 0) dy = 0;
if (!dx && !dy) goto fail;
break;
case EVAS_FILTER_BLUR_GAUSSIAN:
if (dx < 0) dx = 0;
if (dy < 0) dy = 0;
if (!dx && !dy) goto fail;
count = 1;
break;
case EVAS_FILTER_BLUR_BOX:
count = MIN(MAX(1, count), 6);
break;
case EVAS_FILTER_BLUR_DEFAULT:
count = 1;
/* In DEFAULT mode we cheat, depending on the size of the kernel:
* For 1px to 2px, use true Gaussian blur.
* For 3px to 6px, use two Box blurs.
* For more than 6px, use three Box blurs.
* This will give both nicer and MUCH faster results than Gaussian.
*
* NOTE: When implementing blur with GL shaders, other tricks will be
* needed, of course!
*/
{
int tmp_out = outbuf;
int tmp_in = inbuf;
int tmp_ox = ox;
int tmp_oy = oy;
id = -1;
if (dx && dy)
{
tmp = evas_filter_temporary_buffer_get(ctx, 0, 0, EINA_TRUE);
if (!tmp) goto fail;
tmp_in = tmp_out = tmp->id;
tmp_ox = tmp_oy = 0;
}
if (dx)
{
if (dx <= 2)
type = EVAS_FILTER_BLUR_GAUSSIAN;
else
type = EVAS_FILTER_BLUR_BOX;
id = evas_filter_command_blur_add(ctx, drawctx, inbuf, tmp_out,
type, dx, 0, tmp_ox, tmp_oy, 0);
if (id < 0) goto fail;
cmd = _evas_filter_command_get(ctx, id);
cmd->blur.auto_count = EINA_TRUE;
}
if (dy)
{
if (dy <= 2)
type = EVAS_FILTER_BLUR_GAUSSIAN;
else
type = EVAS_FILTER_BLUR_BOX;
id = evas_filter_command_blur_add(ctx, drawctx, inbuf, tmp_in,
type, 0, dy, ox, oy, 0);
if (id < 0) goto fail;
cmd = _evas_filter_command_get(ctx, id);
cmd->blur.auto_count = EINA_TRUE;
}
return id;
}
break;
default:
CRI("Not implemented yet!");
goto fail;
@ -1031,6 +1092,7 @@ evas_filter_command_blur_add(Evas_Filter_Context *ctx, void *drawctx,
cmd->blur.type = type;
cmd->blur.dx = dx;
cmd->blur.dy = 0;
cmd->blur.count = count;
DRAW_COLOR_SET(R, G, B, A);
ret = cmd->id;
}
@ -1043,6 +1105,7 @@ evas_filter_command_blur_add(Evas_Filter_Context *ctx, void *drawctx,
cmd->blur.type = type;
cmd->blur.dx = 0;
cmd->blur.dy = dy;
cmd->blur.count = count;
DRAW_COLOR_SET(R, G, B, A);
if (ret <= 0) ret = cmd->id;
}
@ -1157,7 +1220,7 @@ evas_filter_command_grow_add(Evas_Filter_Context *ctx, void *draw_context,
blurcmd = evas_filter_command_blur_add(ctx, draw_context, inbuf, growbuf,
EVAS_FILTER_BLUR_DEFAULT,
abs(radius), abs(radius), 0, 0);
abs(radius), abs(radius), 0, 0, 0);
if (blurcmd < 0) return -1;
if (diam > 255) diam = 255;

View File

@ -1018,8 +1018,9 @@ _blur_padding_update(Evas_Filter_Program *pgm, Evas_Filter_Instruction *instr,
int *padl, int *padr, int *padt, int *padb)
{
Eina_Bool yset = EINA_FALSE;
int rx, ry, ox, oy, l, r, t, b;
const char *inbuf, *outbuf;
int rx, ry, ox, oy, l, r, t, b, count;
const char *inbuf, *outbuf, *typestr;
Evas_Filter_Blur_Type type = EVAS_FILTER_BLUR_DEFAULT;
Buffer *in, *out;
rx = _instruction_param_geti(instr, "rx", NULL);
@ -1028,6 +1029,11 @@ _blur_padding_update(Evas_Filter_Program *pgm, Evas_Filter_Instruction *instr,
oy = _instruction_param_geti(instr, "oy", NULL);
inbuf = _instruction_param_gets(instr, "src", NULL);
outbuf = _instruction_param_gets(instr, "dst", NULL);
count = _instruction_param_geti(instr, "count", NULL);
typestr = _instruction_param_gets(instr, "type", NULL);
if (typestr && !strcasecmp(typestr, "box"))
type = EVAS_FILTER_BLUR_BOX;
in = _buffer_get(pgm, inbuf);
out = _buffer_get(pgm, outbuf);
@ -1038,6 +1044,17 @@ _blur_padding_update(Evas_Filter_Program *pgm, Evas_Filter_Instruction *instr,
if (rx < 0) rx = 0;
if (ry < 0) ry = 0;
if (type == EVAS_FILTER_BLUR_BOX)
{
if (count < 1) count = 1;
if (count > 6) count = 3;
}
else
count = 1;
rx *= count;
ry *= count;
l = rx + in->pad.l + ((ox < 0) ? (-ox) : 0);
r = rx + in->pad.r + ((ox > 0) ? ox : 0);
t = ry + in->pad.t + ((oy < 0) ? (-oy) : 0);
@ -1067,7 +1084,7 @@ _blur_padding_update(Evas_Filter_Program *pgm, Evas_Filter_Instruction *instr,
@param rx X radius. Specifies the radius of the blurring kernel (X direction).
@param ry Y radius. Specifies the radius of the blurring kernel (Y direction). If -1 is used, then @a ry = @a rx.
@param type Blur type to apply. One of @c default, @c box or @c gaussian. @c default is an alias for @c gaussian.
@param type Blur type to apply. One of @c default, @c box or @c gaussian. See below for details about @c default.
@param ox X offset. Moves the buffer to the right (@a ox > 0) or to the left (@a ox < 0) by N pixels.
@param oy Y offset. Moves the buffer to the bottom (@a oy > 0) or to the top (@a oy < 0) by N pixels.
@param color A color to use for alpha to RGBA conversion. See @ref evasfilters_color "colors". <br>
@ -1075,6 +1092,15 @@ _blur_padding_update(Evas_Filter_Program *pgm, Evas_Filter_Instruction *instr,
draw the buffer in this color.
@param src Source buffer to blur.
@param dst Destination buffer for blending.
@param count Number of times to repeat the blur. Only valid with @c box blur. Valid range is: 1 to 6.
The blur type @c default is <b>recommended in all situations</b> as it will select the smoothest
and fastest operation possible depending on the kernel size. Instead of running a real
gaussian blur, 2 or 3 box blurs may be chained to produce a similar effect at a much
higher speed. The value @a count can be set to a value from 1 to 6 if blur type @c box
has been specified.
The speedups of @c box over @c gaussian are of orders of 4x to more than 20x faster.
If @a src is an alpha buffer and @a dst is an RGBA buffer, then the color option should be set.
@ -1105,6 +1131,7 @@ _blur_instruction_prepare(Evas_Filter_Instruction *instr)
_instruction_param_name_add(instr, "color", VT_COLOR, 0xFFFFFFFF);
_instruction_param_name_add(instr, "src", VT_BUFFER, "input");
_instruction_param_name_add(instr, "dst", VT_BUFFER, "output");
_instruction_param_name_add(instr, "count", VT_INT, 0);
return EINA_TRUE;
}
@ -1947,12 +1974,12 @@ static int
_instr2cmd_blur(Evas_Filter_Context *ctx, Evas_Filter_Program *pgm,
Evas_Filter_Instruction *instr, void *dc)
{
Eina_Bool isset = EINA_FALSE, yset = EINA_FALSE;
Eina_Bool colorset = EINA_FALSE, yset = EINA_FALSE, cntset = EINA_FALSE;
Evas_Filter_Blur_Type type = EVAS_FILTER_BLUR_DEFAULT;
const char *src, *dst, *typestr;
DATA32 color;
Buffer *in, *out;
int cmdid, ox, oy, rx, ry, A, R, G, B;
int cmdid, ox, oy, rx, ry, A, R, G, B, count;
src = _instruction_param_gets(instr, "src", NULL);
dst = _instruction_param_gets(instr, "dst", NULL);
@ -1960,8 +1987,9 @@ _instr2cmd_blur(Evas_Filter_Context *ctx, Evas_Filter_Program *pgm,
oy = _instruction_param_geti(instr, "oy", NULL);
rx = _instruction_param_geti(instr, "rx", NULL);
ry = _instruction_param_geti(instr, "ry", &yset);
color = _instruction_param_getc(instr, "color", &isset);
color = _instruction_param_getc(instr, "color", &colorset);
typestr = _instruction_param_gets(instr, "type", NULL);
count = _instruction_param_geti(instr, "count", &cntset);
in = _buffer_get(pgm, src);
out = _buffer_get(pgm, dst);
@ -1977,11 +2005,26 @@ _instr2cmd_blur(Evas_Filter_Context *ctx, Evas_Filter_Program *pgm,
ERR("Unknown blur type '%s'. Using default blur.", typestr);
}
if (type == EVAS_FILTER_BLUR_BOX)
{
if (count < 1) count = 1;
if (count > 6)
{
WRN("Box blur count should be below 6, defaults to 3.");
count = 3;
}
}
else
{
if (cntset) WRN("Blur count can only be used with BOX blur.");
count = 1;
}
if (!yset) ry = rx;
if (isset) SETCOLOR(color);
if (colorset) SETCOLOR(color);
cmdid = evas_filter_command_blur_add(ctx, dc, in->cid, out->cid, type,
rx, ry, ox, oy);
if (isset) RESETCOLOR();
rx, ry, ox, oy, count);
if (colorset) RESETCOLOR();
return cmdid;
}

View File

@ -126,7 +126,9 @@ struct _Evas_Filter_Command
struct
{
int dx, dy;
int count;
Evas_Filter_Blur_Type type;
Eina_Bool auto_count : 1; // If true, BOX blur will be smooth using
} blur;
struct

View File

@ -42,10 +42,10 @@ enum _Evas_Filter_Mode
enum _Evas_Filter_Blur_Type
{
EVAS_FILTER_BLUR_GAUSSIAN = 0x0, // Gaussian or sine curve. O(nm)
EVAS_FILTER_BLUR_DEFAULT = 0x0, // Default blur (GAUSSIAN or series of BOX)
EVAS_FILTER_BLUR_BOX = 0x1, // Optimizable on CPU. But, UGLY. O(n)
EVAS_FILTER_BLUR_GAUSSIAN = 0x2, // Gaussian blur (using sine curve)
EVAS_FILTER_BLUR_LAST,
EVAS_FILTER_BLUR_DEFAULT = EVAS_FILTER_BLUR_GAUSSIAN
};
enum _Evas_Filter_Channel
@ -141,9 +141,10 @@ int evas_filter_command_blend_add(Evas_Filter_Context *ctx,
* @param dy Y radius of blur. Can be negative ONLY for MOTION blur
* @param ox X offset in the destination buffer
* @param oy Y offset in the destination buffer
* @param count Number of times to repeat the operation (used for smooth fast blurs with box blur)
* @return Filter command ID or -1 in case of error
*/
int evas_filter_command_blur_add(Evas_Filter_Context *ctx, void *draw_context, int inbuf, int outbuf, Evas_Filter_Blur_Type type, int dx, int dy, int ox, int oy);
int evas_filter_command_blur_add(Evas_Filter_Context *ctx, void *draw_context, int inbuf, int outbuf, Evas_Filter_Blur_Type type, int dx, int dy, int ox, int oy, int count);
/**
* @brief Fill a buffer with the current color