jpeg pushed a commit to branch master.

http://git.enlightenment.org/core/efl.git/commit/?id=2a1ba1b9086bdf9d3d474ec7f8a5cfe37fcdd61a

commit 2a1ba1b9086bdf9d3d474ec7f8a5cfe37fcdd61a
Author: Jean-Philippe Andre <jp.an...@samsung.com>
Date:   Tue Mar 11 18:21:46 2014 +0900

    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.
---
 src/lib/evas/filters/evas_filter.c         | 81 ++++++++++++++++++++++++++----
 src/lib/evas/filters/evas_filter_parser.c  | 61 ++++++++++++++++++----
 src/lib/evas/filters/evas_filter_private.h |  2 +
 src/lib/evas/include/evas_filter.h         |  7 +--
 4 files changed, 130 insertions(+), 21 deletions(-)

diff --git a/src/lib/evas/filters/evas_filter.c 
b/src/lib/evas/filters/evas_filter.c
index b3f5836..6e899a9 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_GAUSSIAN:
+        count = 1;
+        break;
+
       case EVAS_FILTER_BLUR_BOX:
-        if (dx < 0) dx = 0;
-        if (dy < 0) dy = 0;
-        if (!dx && !dy) goto fail;
+        count = MIN(MAX(1, count), 6);
         break;
-      case EVAS_FILTER_BLUR_GAUSSIAN:
-        if (dx < 0) dx = 0;
-        if (dy < 0) dy = 0;
-        if (!dx && !dy) goto fail;
+
+      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 907d7b5..ce7e45d 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". <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;
 }
diff --git a/src/lib/evas/filters/evas_filter_private.h 
b/src/lib/evas/filters/evas_filter_private.h
index 6255be4..e4b83a8 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 5445058..052617e 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

-- 


Reply via email to