forked from enlightenment/efl
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:
parent
4e249143a5
commit
2a1ba1b908
|
@ -898,7 +898,7 @@ evas_filter_command_fill_add(Evas_Filter_Context *ctx, void *draw_context,
|
||||||
int
|
int
|
||||||
evas_filter_command_blur_add(Evas_Filter_Context *ctx, void *drawctx,
|
evas_filter_command_blur_add(Evas_Filter_Context *ctx, void *drawctx,
|
||||||
int inbuf, int outbuf, Evas_Filter_Blur_Type type,
|
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_Command *cmd = NULL;
|
||||||
Evas_Filter_Buffer *in = NULL, *out = NULL, *tmp = NULL, *in_dy = 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(ctx, -1);
|
||||||
EINA_SAFETY_ON_NULL_RETURN_VAL(drawctx, -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)
|
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:
|
case EVAS_FILTER_BLUR_GAUSSIAN:
|
||||||
if (dx < 0) dx = 0;
|
count = 1;
|
||||||
if (dy < 0) dy = 0;
|
|
||||||
if (!dx && !dy) goto fail;
|
|
||||||
break;
|
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:
|
default:
|
||||||
CRI("Not implemented yet!");
|
CRI("Not implemented yet!");
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@ -1031,6 +1092,7 @@ evas_filter_command_blur_add(Evas_Filter_Context *ctx, void *drawctx,
|
||||||
cmd->blur.type = type;
|
cmd->blur.type = type;
|
||||||
cmd->blur.dx = dx;
|
cmd->blur.dx = dx;
|
||||||
cmd->blur.dy = 0;
|
cmd->blur.dy = 0;
|
||||||
|
cmd->blur.count = count;
|
||||||
DRAW_COLOR_SET(R, G, B, A);
|
DRAW_COLOR_SET(R, G, B, A);
|
||||||
ret = cmd->id;
|
ret = cmd->id;
|
||||||
}
|
}
|
||||||
|
@ -1043,6 +1105,7 @@ evas_filter_command_blur_add(Evas_Filter_Context *ctx, void *drawctx,
|
||||||
cmd->blur.type = type;
|
cmd->blur.type = type;
|
||||||
cmd->blur.dx = 0;
|
cmd->blur.dx = 0;
|
||||||
cmd->blur.dy = dy;
|
cmd->blur.dy = dy;
|
||||||
|
cmd->blur.count = count;
|
||||||
DRAW_COLOR_SET(R, G, B, A);
|
DRAW_COLOR_SET(R, G, B, A);
|
||||||
if (ret <= 0) ret = cmd->id;
|
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,
|
blurcmd = evas_filter_command_blur_add(ctx, draw_context, inbuf, growbuf,
|
||||||
EVAS_FILTER_BLUR_DEFAULT,
|
EVAS_FILTER_BLUR_DEFAULT,
|
||||||
abs(radius), abs(radius), 0, 0);
|
abs(radius), abs(radius), 0, 0, 0);
|
||||||
if (blurcmd < 0) return -1;
|
if (blurcmd < 0) return -1;
|
||||||
|
|
||||||
if (diam > 255) diam = 255;
|
if (diam > 255) diam = 255;
|
||||||
|
|
|
@ -1018,8 +1018,9 @@ _blur_padding_update(Evas_Filter_Program *pgm, Evas_Filter_Instruction *instr,
|
||||||
int *padl, int *padr, int *padt, int *padb)
|
int *padl, int *padr, int *padt, int *padb)
|
||||||
{
|
{
|
||||||
Eina_Bool yset = EINA_FALSE;
|
Eina_Bool yset = EINA_FALSE;
|
||||||
int rx, ry, ox, oy, l, r, t, b;
|
int rx, ry, ox, oy, l, r, t, b, count;
|
||||||
const char *inbuf, *outbuf;
|
const char *inbuf, *outbuf, *typestr;
|
||||||
|
Evas_Filter_Blur_Type type = EVAS_FILTER_BLUR_DEFAULT;
|
||||||
Buffer *in, *out;
|
Buffer *in, *out;
|
||||||
|
|
||||||
rx = _instruction_param_geti(instr, "rx", NULL);
|
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);
|
oy = _instruction_param_geti(instr, "oy", NULL);
|
||||||
inbuf = _instruction_param_gets(instr, "src", NULL);
|
inbuf = _instruction_param_gets(instr, "src", NULL);
|
||||||
outbuf = _instruction_param_gets(instr, "dst", 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);
|
in = _buffer_get(pgm, inbuf);
|
||||||
out = _buffer_get(pgm, outbuf);
|
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 (rx < 0) rx = 0;
|
||||||
if (ry < 0) ry = 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);
|
l = rx + in->pad.l + ((ox < 0) ? (-ox) : 0);
|
||||||
r = rx + in->pad.r + ((ox > 0) ? ox : 0);
|
r = rx + in->pad.r + ((ox > 0) ? ox : 0);
|
||||||
t = ry + in->pad.t + ((oy < 0) ? (-oy) : 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 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 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 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 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>
|
@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.
|
draw the buffer in this color.
|
||||||
@param src Source buffer to blur.
|
@param src Source buffer to blur.
|
||||||
@param dst Destination buffer for blending.
|
@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.
|
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, "color", VT_COLOR, 0xFFFFFFFF);
|
||||||
_instruction_param_name_add(instr, "src", VT_BUFFER, "input");
|
_instruction_param_name_add(instr, "src", VT_BUFFER, "input");
|
||||||
_instruction_param_name_add(instr, "dst", VT_BUFFER, "output");
|
_instruction_param_name_add(instr, "dst", VT_BUFFER, "output");
|
||||||
|
_instruction_param_name_add(instr, "count", VT_INT, 0);
|
||||||
|
|
||||||
return EINA_TRUE;
|
return EINA_TRUE;
|
||||||
}
|
}
|
||||||
|
@ -1947,12 +1974,12 @@ static int
|
||||||
_instr2cmd_blur(Evas_Filter_Context *ctx, Evas_Filter_Program *pgm,
|
_instr2cmd_blur(Evas_Filter_Context *ctx, Evas_Filter_Program *pgm,
|
||||||
Evas_Filter_Instruction *instr, void *dc)
|
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;
|
Evas_Filter_Blur_Type type = EVAS_FILTER_BLUR_DEFAULT;
|
||||||
const char *src, *dst, *typestr;
|
const char *src, *dst, *typestr;
|
||||||
DATA32 color;
|
DATA32 color;
|
||||||
Buffer *in, *out;
|
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);
|
src = _instruction_param_gets(instr, "src", NULL);
|
||||||
dst = _instruction_param_gets(instr, "dst", 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);
|
oy = _instruction_param_geti(instr, "oy", NULL);
|
||||||
rx = _instruction_param_geti(instr, "rx", NULL);
|
rx = _instruction_param_geti(instr, "rx", NULL);
|
||||||
ry = _instruction_param_geti(instr, "ry", &yset);
|
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);
|
typestr = _instruction_param_gets(instr, "type", NULL);
|
||||||
|
count = _instruction_param_geti(instr, "count", &cntset);
|
||||||
in = _buffer_get(pgm, src);
|
in = _buffer_get(pgm, src);
|
||||||
out = _buffer_get(pgm, dst);
|
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);
|
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 (!yset) ry = rx;
|
||||||
if (isset) SETCOLOR(color);
|
if (colorset) SETCOLOR(color);
|
||||||
cmdid = evas_filter_command_blur_add(ctx, dc, in->cid, out->cid, type,
|
cmdid = evas_filter_command_blur_add(ctx, dc, in->cid, out->cid, type,
|
||||||
rx, ry, ox, oy);
|
rx, ry, ox, oy, count);
|
||||||
if (isset) RESETCOLOR();
|
if (colorset) RESETCOLOR();
|
||||||
|
|
||||||
return cmdid;
|
return cmdid;
|
||||||
}
|
}
|
||||||
|
|
|
@ -126,7 +126,9 @@ struct _Evas_Filter_Command
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
int dx, dy;
|
int dx, dy;
|
||||||
|
int count;
|
||||||
Evas_Filter_Blur_Type type;
|
Evas_Filter_Blur_Type type;
|
||||||
|
Eina_Bool auto_count : 1; // If true, BOX blur will be smooth using
|
||||||
} blur;
|
} blur;
|
||||||
|
|
||||||
struct
|
struct
|
||||||
|
|
|
@ -42,10 +42,10 @@ enum _Evas_Filter_Mode
|
||||||
|
|
||||||
enum _Evas_Filter_Blur_Type
|
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_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_LAST,
|
||||||
EVAS_FILTER_BLUR_DEFAULT = EVAS_FILTER_BLUR_GAUSSIAN
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum _Evas_Filter_Channel
|
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 dy Y radius of blur. Can be negative ONLY for MOTION blur
|
||||||
* @param ox X offset in the destination buffer
|
* @param ox X offset in the destination buffer
|
||||||
* @param oy Y 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
|
* @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
|
* @brief Fill a buffer with the current color
|
||||||
|
|
Loading…
Reference in New Issue