diff --git a/src/lib/evas/filters/evas_filter.c b/src/lib/evas/filters/evas_filter.c
index b3f5836025..6e899a901b 100644
--- a/src/lib/evas/filters/evas_filter.c
+++ b/src/lib/evas/filters/evas_filter.c
@@ -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;
diff --git a/src/lib/evas/filters/evas_filter_parser.c b/src/lib/evas/filters/evas_filter_parser.c
index 907d7b51a4..ce7e45d40d 100644
--- a/src/lib/evas/filters/evas_filter_parser.c
+++ b/src/lib/evas/filters/evas_filter_parser.c
@@ -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".
@@ -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 recommended in all situations 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;
}
diff --git a/src/lib/evas/filters/evas_filter_private.h b/src/lib/evas/filters/evas_filter_private.h
index 6255be40d0..e4b83a8291 100644
--- a/src/lib/evas/filters/evas_filter_private.h
+++ b/src/lib/evas/filters/evas_filter_private.h
@@ -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
diff --git a/src/lib/evas/include/evas_filter.h b/src/lib/evas/include/evas_filter.h
index 5445058545..052617e48f 100644
--- a/src/lib/evas/include/evas_filter.h
+++ b/src/lib/evas/include/evas_filter.h
@@ -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