Evas: Filters:
authornash <nash@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Tue, 19 Apr 2011 05:47:56 +0000 (05:47 +0000)
committernash <nash@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Tue, 19 Apr 2011 05:47:56 +0000 (05:47 +0000)
More work, proudly supported by Samsung.  Filters!

So now you can apply a whole host of cheesy visual effects to objects at
runtime.  This is the first commit, there are a couple of more to come as I
tweak the filters, and fix blur with GL[1].

Please direct bugs to me nash@nash.id.au.

[1] You'd think shaders would be good at this.. but no, generic blur and GL
are like trying to get an apple product to work with Linux.

git-svn-id: svn+ssh://svn.enlightenment.org/var/svn/e/trunk/evas@58726 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33

25 files changed:
ChangeLog
src/lib/Evas.h
src/lib/canvas/Makefile.am
src/lib/canvas/evas_filter.c [new file with mode: 0644]
src/lib/engines/common/evas_image_main.c
src/lib/include/evas_common.h
src/lib/include/evas_private.h
src/modules/engines/gl_common/Makefile.am
src/modules/engines/gl_common/evas_gl_common.h
src/modules/engines/gl_common/evas_gl_context.c
src/modules/engines/gl_common/evas_gl_filter.c [new file with mode: 0644]
src/modules/engines/gl_common/evas_gl_image.c
src/modules/engines/gl_common/evas_gl_shader.c
src/modules/engines/gl_common/shader/filter_blur.h [new file with mode: 0644]
src/modules/engines/gl_common/shader/filter_blur.shd [new file with mode: 0644]
src/modules/engines/gl_common/shader/filter_blur_bgra.h [new file with mode: 0644]
src/modules/engines/gl_common/shader/filter_blur_bgra.shd [new file with mode: 0644]
src/modules/engines/gl_common/shader/filter_blur_bgra_nomul.h [new file with mode: 0644]
src/modules/engines/gl_common/shader/filter_blur_bgra_nomul.shd [new file with mode: 0644]
src/modules/engines/gl_common/shader/filter_blur_nomul.h [new file with mode: 0644]
src/modules/engines/gl_common/shader/filter_blur_nomul.shd [new file with mode: 0644]
src/modules/engines/gl_common/shader/filter_blur_vert.h [new file with mode: 0644]
src/modules/engines/gl_common/shader/filter_blur_vert.shd [new file with mode: 0644]
src/modules/engines/gl_x11/evas_engine.c
src/modules/engines/software_generic/evas_engine.c

index ebb408c..2515899 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
          useful for "to" field of email/sms applications where ',' is used to
          separate different text entities.
 
+2011-04-19 Brett Nash (nash)
+
+       * Filters: So filtering of various flavours.  They work only on images
+         (use a proxy if you want it on other objects).  Documentation inline.
+         Supports a filter object or filter under (the area where the object
+         is filtered).  Various parameters to tweak, and potential for
+         additional filters (but you get to write the shader ;-)
index bf0be2e..29f8914 100644 (file)
@@ -7879,6 +7879,51 @@ EAPI Eina_Accessor                      *evas_object_table_accessor_new    (cons
 EAPI Eina_List                          *evas_object_table_children_get    (const Evas_Object *o) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_MALLOC;
    EAPI Evas_Object                        *evas_object_table_child_get       (const Evas_Object *o, unsigned short col, unsigned short row) EINA_ARG_NONNULL(1);
 
+   typedef enum
+     {
+       /** Apply any filter effects to this object (Default) */
+        EVAS_FILTER_MODE_OBJECT,
+       /** Filter all objects beneath this object on the canvas */
+       EVAS_FILTER_MODE_BELOW,
+     } Evas_Filter_Mode;
+   typedef enum
+     {
+       /** No filter: Default */
+       EVAS_FILTER_NONE,
+       /** A blur filter.  Params are quality (float), and radius (int). */
+       EVAS_FILTER_BLUR,
+       /** Negates the colors of an image.  Also called solarize */
+       EVAS_FILTER_INVERT,
+       EVAS_FILTER_SOLARIZE = EVAS_FILTER_INVERT,
+       /** Makes a sepia version of the image. */
+       EVAS_FILTER_SEPIA,
+       /** Makes a greyscale version of the image.  Params are 'red',
+        * 'green', 'blue' (all floats) which must add to 1.  The defaults are
+        * 0.3, 0.59 and 0.11 which approximates human vision. Setting 'all'
+        * sets rgb to the same value. */
+       EVAS_FILTER_GREYSCALE,
+       EVAS_FILTER_GRAYSCALE = EVAS_FILTER_GREYSCALE,
+       /** Brighten (or darken) image.  Param 'adjust' float (-1.0 to 1.0)
+        * amount to adjust. */
+       EVAS_FILTER_BRIGHTNESS,
+       /** Enhance contrast on image.  Param 'adjust' float (-1.0 to 1.0)
+        * amount to adjust. */
+       EVAS_FILTER_CONTRAST,
+
+       EVAS_FILTER_LAST = EVAS_FILTER_CONTRAST
+     } Evas_Filter;
+
+   EAPI Eina_Bool                            evas_object_filter_mode_set      (Evas_Object *o, Evas_Filter_Mode mode);
+   EAPI Evas_Filter_Mode                     evas_object_filter_mode_get      (Evas_Object *o);
+   EAPI Eina_Bool                            evas_object_filter_set           (Evas_Object *o, Evas_Filter filter);
+   EAPI Evas_Filter                          evas_object_filter_get           (Evas_Object *o);
+   EAPI Eina_Bool                            evas_object_filter_param_set_int (Evas_Object *o, const char *param, int val);
+   EAPI int                                  evas_object_filter_param_get_int (Evas_Object *o, const char *param);
+   EAPI Eina_Bool                            evas_object_filter_param_set_str (Evas_Object *o, const char *param, const char *val);
+   EAPI Eina_Bool                            evas_object_filter_param_set_obj (Evas_Object *o, const char *param, Evas_Object *);
+   EAPI Eina_Bool                            evas_object_filter_param_set_float(Evas_Object *o, const char *param, double val);
+
+
 
 /**
  * @defgroup Evas_Cserve Shared Image Cache Server
index 3c7d34f..b408ec2 100644 (file)
@@ -21,6 +21,7 @@ evas_callbacks.c \
 evas_clip.c \
 evas_data.c \
 evas_events.c \
+evas_filter.c \
 evas_focus.c \
 evas_key.c \
 evas_key_grab.c \
diff --git a/src/lib/canvas/evas_filter.c b/src/lib/canvas/evas_filter.c
new file mode 100644 (file)
index 0000000..2f49bec
--- /dev/null
@@ -0,0 +1,1185 @@
+/*
+ * Filter implementation for evas
+ */
+
+#include <stddef.h>     // offsetof
+
+
+#include "evas_common.h"
+#include "evas_private.h"
+
+#include "assert.h"
+
+#ifdef BUILD_NEON
+# define BUILD_NEON0 1
+#else
+# define BUILD_NEON0 0
+#endif
+
+typedef struct Evas_Filter_Info_Blur {
+     double quality;
+     int radius;
+} Evas_Filter_Info_Blur;
+
+typedef struct Evas_Filter_Info_GreyScale {
+     double r,g,b;
+} Evas_Filter_Info_GreyScale;
+typedef struct Evas_Filter_Info_Brightness {
+     double adjust;
+} Evas_Filter_Info_Brightness;
+typedef struct Evas_Filter_Info_Contrast {
+     double adjust;
+} Evas_Filter_Info_Contrast;
+
+
+typedef int (*Filter_Size_FN)(Evas_Filter_Info *,int,int,int*,int*,Eina_Bool);
+typedef uint8_t *(*Key_FN)(const Evas_Filter_Info  *, uint32_t *);
+
+struct fieldinfo {
+   const char *field;
+   int type;
+   size_t offset;
+};
+
+
+struct filterinfo
+{
+   Evas_Software_Filter_Fn filter;
+   const size_t datasize;
+   Filter_Size_FN sizefn;
+   Key_FN keyfn;
+   Eina_Bool alwaysalpha;
+};
+
+enum {
+     TYPE_INT,
+     TYPE_FLOAT
+};
+
+static int blur_size_get(Evas_Filter_Info*, int, int, int *, int *, Eina_Bool);
+static uint8_t *gaussian_key_get(const Evas_Filter_Info *, uint32_t *);
+
+static Eina_Bool gaussian_filter(Evas_Filter_Info *, RGBA_Image*, RGBA_Image*);
+static Eina_Bool negation_filter(Evas_Filter_Info *, RGBA_Image*, RGBA_Image*);
+static Eina_Bool sepia_filter(Evas_Filter_Info *, RGBA_Image*, RGBA_Image*);
+static Eina_Bool greyscale_filter(Evas_Filter_Info*, RGBA_Image*, RGBA_Image*);
+static Eina_Bool brightness_filter(Evas_Filter_Info*, RGBA_Image*, RGBA_Image*);
+static Eina_Bool contrast_filter(Evas_Filter_Info *, RGBA_Image*, RGBA_Image*);
+
+static Eina_Bool negation_filter_neon(Evas_Filter_Info *, RGBA_Image *src, RGBA_Image *);
+
+struct filterinfo filterinfo[] =
+{
+   /* None */
+   { NULL, 0, NULL, NULL, EINA_FALSE},
+   /* Blur */
+   { gaussian_filter, sizeof(Evas_Filter_Info_Blur), blur_size_get,
+               gaussian_key_get, EINA_TRUE },
+   /* Negation */
+   { negation_filter, 0, NULL, NULL, EINA_FALSE },
+   /* Sepia */
+   { sepia_filter, 0, NULL, NULL, EINA_FALSE },
+   /* Greyscale */
+   { greyscale_filter, sizeof(Evas_Filter_Info_GreyScale), NULL, NULL, EINA_FALSE },
+   /* Brightness */
+   { brightness_filter, sizeof(Evas_Filter_Info_Brightness), NULL, NULL, EINA_FALSE },
+   /* Contrast */
+   { contrast_filter, sizeof(Evas_Filter_Info_Contrast), NULL, NULL, EINA_FALSE},
+};
+
+
+static struct fieldinfo blurfields[] = {
+       { "quality",  TYPE_FLOAT, offsetof(Evas_Filter_Info_Blur, quality) },
+       { "radius",  TYPE_INT, offsetof(Evas_Filter_Info_Blur, radius) },
+       { NULL, 0, 0 },
+};
+
+static struct fieldinfo greyfields[] = {
+       { "red",  TYPE_FLOAT, offsetof(Evas_Filter_Info_GreyScale, r) },
+       { "green",  TYPE_FLOAT, offsetof(Evas_Filter_Info_GreyScale, g) },
+       { "blue",  TYPE_FLOAT, offsetof(Evas_Filter_Info_GreyScale, b) },
+
+       { "all",  TYPE_FLOAT, offsetof(Evas_Filter_Info_GreyScale, r) },
+       { "all",  TYPE_FLOAT, offsetof(Evas_Filter_Info_GreyScale, g) },
+       { "all",  TYPE_FLOAT, offsetof(Evas_Filter_Info_GreyScale, b) },
+       { NULL, 0, 0 },
+};
+static struct fieldinfo brightnessfields[] = {
+       { "adjust",  TYPE_FLOAT, offsetof(Evas_Filter_Info_Brightness, adjust) },
+       { NULL, 0, 0 },
+};
+static struct fieldinfo contrastfields[] = {
+       { "adjust",  TYPE_FLOAT, offsetof(Evas_Filter_Info_Contrast, adjust) },
+       { NULL, 0, 0 },
+};
+
+
+
+static struct fieldinfo *filterfields[] =
+{
+   NULL,
+   blurfields,
+   NULL,
+   NULL,
+   greyfields,
+   brightnessfields,
+   contrastfields,
+};
+
+
+static Evas_Filter_Info *filter_alloc(Evas_Object *o);
+
+
+/**
+ * Set the filter mode for an object.
+ *
+ * There are two valid filtering modes currently:
+ *  - EVAS_FILTER_MODE_OBJECT: which applies the filter to the object itself
+ *  - EVAS_FILTER_MODE_BELOW: which makes the object invisible and filters
+ *  what is below the object.
+ *
+ * The default filter mode is EVAS_FILTER_MODE_OBJECT. 
+ *
+ * @param o Object to set filter mode on.
+ * @param mode Mode to set.
+ * @return EINA_TRUE on success, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool
+evas_object_filter_mode_set(Evas_Object *o, Evas_Filter_Mode mode)
+{
+   Evas_Filter_Info *info;
+   if (!o) return EINA_FALSE; /* nash: do Magic check */
+
+   if (mode != EVAS_FILTER_MODE_OBJECT && mode != EVAS_FILTER_MODE_BELOW)
+      return EINA_FALSE;
+
+   if (!o->filter)
+     {
+        filter_alloc(o);
+     }
+   if (!o->filter) return EINA_FALSE;
+   info = o->filter;
+
+   if (info->mode == mode) return EINA_TRUE; /* easy case */
+   info->mode = mode;
+   info->dirty = 1;
+   return EINA_TRUE;
+}
+
+/**
+ * Get the current filtering mode for an object.
+ *
+ * By default all objects are in object filtering mode, even if no filter is
+ * set.
+ *
+ * @param o Object to get filter mode of.
+ * @return Filter mode (default EVAS_FILTER_MODE_OBJECT)
+ */
+EAPI Evas_Filter_Mode
+evas_object_filter_mode_get(Evas_Object *o)
+{
+   if (!o) return EVAS_FILTER_MODE_OBJECT; /* nash magic */
+   if (!o->filter) filter_alloc(o);
+   if (!o->filter) return EVAS_FILTER_MODE_OBJECT;
+   return o->filter->mode;
+}
+
+/**
+ * Set the current filter type.
+ *
+ * This sets the filter type, whether a blur, color filter or some other type
+ * of filter.  This is normally the only filter call necessary, although some
+ * filters require additional parameters.
+ *
+ * If the object has a filter already, and existing parameters will be
+ * cleared.
+ *
+ * Setting the blur to EVAS_FILTER_NONE removes any filter.
+ *
+ * @param o Object to set the filter on.
+ * @param filter Filter to set.
+ * @return EINA_TRUE On success
+ */
+EAPI Eina_Bool
+evas_object_filter_set(Evas_Object *o, Evas_Filter filter)
+{
+   Evas_Filter_Info *info;
+   struct filterinfo *finfo;
+
+
+   if (!o) return EINA_FALSE; /* nash: magic */
+
+   /* force filter to be signed: else gcc complains, but enums may always be
+    * signed */
+   if ((int)filter < (int)EVAS_FILTER_NONE || filter > EVAS_FILTER_LAST)
+      return EINA_FALSE;
+
+   if (!o->filter) filter_alloc(o);
+   if (!o->filter) return EINA_FALSE;
+
+   info = o->filter;
+
+   if (info->filter == filter) return EINA_TRUE;
+
+   finfo = filterinfo + filter;
+   info->filter = filter;
+   info->dirty = 1;
+   if (info->data)
+     {
+        if (info->data_free)
+           info->data_free(info->data);
+        else
+           free(info->data);
+     }
+   info->datalen = finfo->datasize;
+   if (finfo->datasize)
+      info->data = calloc(1,finfo->datasize);
+   else
+      info->data = NULL;
+   info->data_free = NULL;
+
+   return EINA_TRUE;
+}
+
+
+/**
+ * Get the current filter.
+ *
+ * @param o Object to get filter of.
+ * @return The filter if set, or EVAS_FILTER_NONE.
+ */
+EAPI Evas_Filter
+evas_object_filter_get(Evas_Object *o)
+{
+   if (!o || !o->filter) return EVAS_FILTER_NONE;
+
+   return o->filter->filter;
+}
+
+/**
+ * Set an integer parameter of a filter.
+ *
+ * This sets an integer parameter of a filter, if such parameter is known to
+ * the filter.  Note that some parameters may actually set multiple fields.
+ * The individual filters define the specific parameters available.
+ *
+ * It should be noted that filter parameters are lost after the filter type
+ * changes, so set the filter type, then the parameters.
+ *
+ * @param o Object to set parameter on.
+ * @param param Name of parameter to set.
+ * @param val Value to set.
+ * @return EINA_TRUE if at least one parameter was set, EINA_FALSE
+ * otherwise.
+ */
+EAPI Eina_Bool
+evas_object_filter_param_set_int(Evas_Object *o, const char *param, int val)
+{
+   char *data;
+   const struct fieldinfo *fields;
+   Eina_Bool found;
+   int i;
+
+
+   if (!o || !o->filter || !o->filter->data) return EINA_FALSE;
+
+   fields = filterfields[o->filter->filter];
+   data = o->filter->data;
+
+   found = EINA_FALSE;
+
+   for (i = 0 ; fields[i].field ; i ++)
+     {
+        if (strcmp(fields[i].field, param) == 0)
+          {
+             if (fields[i].type != TYPE_INT) continue;
+             *(int *)(data + fields[i].offset) = val;
+             o->filter->dirty = 1;
+             evas_object_change(o);
+             found = EINA_TRUE;
+          }
+     }
+
+   return found;
+}
+
+/**
+ * Get an integer value parameter from a filter.
+ *
+ * Gets the first matching parameter for a filter.  Note there is no way to
+ * later fields if they do not have their own accessor name.
+ *
+ * Also note that there is no way to tell the difference between a -1 as a
+ * value, and the error code.  Ask your filter writer to use a different
+ * range.
+ *
+ * @param o The object.
+ * @Param param Name of the parameter to get.
+ * @return The value, or -1 on error.
+ */
+EAPI int
+evas_object_filter_param_get_int(Evas_Object *o, const char *param)
+{
+   char *data;
+   const struct fieldinfo *fields;
+   int val;
+   int i;
+
+   if (!o || !o->filter || !o->filter->data) return -1;
+
+   fields = blurfields;
+   data = o->filter->data;
+
+   for (i = 0 ; fields[i].field ; i ++)
+     {
+        if (strcmp(fields[i].field, param) == 0)
+          {
+             if (fields[i].type != TYPE_INT) continue;
+             val = *(int *)(data + fields[i].offset);
+             return val;
+          }
+     }
+
+   return -1;
+}
+
+EAPI Eina_Bool
+evas_object_filter_param_set_str(Evas_Object *o, const char *param,
+                                 const char *val)
+{
+   return EINA_FALSE;
+}
+
+EAPI Eina_Bool
+evas_object_filter_param_set_obj(Evas_Object *o, const char *param,
+                                 Evas_Object *val)
+{
+   return EINA_FALSE;
+}
+
+/**
+ * Set a float parameter of a filter.
+ *
+ * This is the same as evas_object_filter_param_get_int(), but for floating
+ * point values.
+ *
+ * @param o Object to set value on.
+ * @param param Name of the parameter to set.
+ * @param EINA_TRUE if at least one parameter was set, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool
+evas_object_filter_param_set_float(Evas_Object *o, const char *param,
+                                   double val)
+{
+   char *data;
+   const struct fieldinfo *fields;
+   int i;
+   Eina_Bool rv;
+
+   if (!o || !o->filter || !o->filter->data) return EINA_FALSE;
+
+   rv = EINA_FALSE;
+   fields = blurfields;
+   data = o->filter->data;
+
+   for (i = 0 ; fields[i].field ; i ++)
+     {
+        if (strcmp(fields[i].field, param) == 0)
+          {
+             if (fields[i].type != TYPE_FLOAT) continue;
+             *(double *)(data + fields[i].offset) = val;
+             o->filter->dirty = 1;
+             o->changed = 1;
+             evas_object_change(o);
+             rv = EINA_TRUE;
+          }
+     }
+
+   return rv;
+}
+
+/*
+ * Internal call
+ */
+int
+evas_filter_get_size(Evas_Filter_Info *info, int inw, int inh,
+                     int *outw, int *outh, Eina_Bool inv)
+{
+   if (!info) return -1;
+   if (!outw && !outh) return 0;
+
+   if (filterinfo[info->filter].sizefn)
+      return filterinfo[info->filter].sizefn(info, inw, inh, outw, outh, inv);
+
+   if (outw) *outw = inw;
+   if (outh) *outh = inh;
+   return 0;
+}
+
+Eina_Bool
+evas_filter_always_alpha(Evas_Filter_Info *info)
+{
+   if (!info) return EINA_FALSE;
+   return filterinfo[info->filter].alwaysalpha;
+}
+
+/*
+ * Another internal call:
+ *    Given a filterinfo, generate a unique key for it
+ *
+ * For simple filters, it's just the filter type.
+ * for more complex filters, it's the type, with it's params.
+ *
+ * Note management of the key data is up to the caller, that is it should
+ * probably be freed after use.
+ *
+ * Note the automatic fallback generation places the single byte at the end so
+ * the memcpy will be aligned.  Micro-optimisations FTW!
+ *
+ * @param info Filter info to generate from
+ * @param len Length of the buffer returned.
+ * @return key KEy buffer
+ */
+uint8_t *
+evas_filter_key_get(const Evas_Filter_Info *info, uint32_t *lenp)
+{
+   struct filterinfo *finfo;
+   uint8_t *key;
+   int len;
+   if (!info) return NULL;
+
+   finfo = filterinfo + info->filter;
+
+   if (finfo->keyfn)
+      return finfo->keyfn(info, lenp);
+
+   len = 1 + finfo->datasize;
+   key = malloc(len);
+   if (finfo->datasize) memcpy(key, info->data, finfo->datasize);
+   key[finfo->datasize] = info->filter;
+
+   return key;
+}
+
+
+static int
+blur_size_get(Evas_Filter_Info *info, int inw, int inh, int *outw, int *outh,
+              Eina_Bool inv){
+   Evas_Filter_Info_Blur *blur;
+
+   blur = info->data;
+
+   if (inv)
+     {
+        if (outw) *outw = MAX(inw - blur->radius * 2, 0);
+        if (outh) *outh = MAX(inh - blur->radius * 2, 0);
+     }
+   else
+     {
+        if (outw) *outw = inw + blur->radius * 2;
+        if (outh) *outh = inh + blur->radius * 2;
+     }
+   return 0;
+}
+
+/**
+ * Generate a key for the Gaussian generator.
+ *
+ * The size is:
+ *    - 1 byte for the type (blur)
+ *    - 1 byte for the quality (0-1 -> 0-255)
+ *    - 2 bytes for radius (max is 508 anyway)
+ *
+ * @param info Filter info
+ * @param len Length of the returned buffer
+ * @return new buffer
+ */
+static uint8_t *
+gaussian_key_get(const Evas_Filter_Info *info, uint32_t *lenp)
+{
+   struct Evas_Filter_Info_Blur *blur;
+   uint8_t *key;
+
+   if (!info || !info->data) return NULL;
+   blur = info->data;
+
+   if (lenp) *lenp = 4;
+   key = malloc(4);
+   key[0] = EVAS_FILTER_BLUR;
+   key[1] = blur->quality * 255;
+   key[2] = blur->radius >> 8;
+   key[3] = blur->radius;
+
+   return key;
+}
+
+
+Evas_Software_Filter_Fn
+evas_filter_software_get(Evas_Filter_Info *info)
+{
+   return filterinfo[info->filter].filter;
+}
+
+
+
+
+/*
+ * Private calls
+ */
+static Evas_Filter_Info *
+filter_alloc(Evas_Object *o)
+{
+   Evas_Filter_Info *info;
+   if (!o) return NULL;
+
+   info = calloc(1,sizeof(struct Evas_Filter_Info));
+   info->dirty = 1;
+   info->filter = EVAS_FILTER_NONE;
+   info->mode = EVAS_FILTER_MODE_OBJECT;
+   info->datalen = 0;
+
+   o->filter = info;
+
+   return info;
+}
+
+/**
+ * Software implementations
+ */
+
+#define alpha(x)       (((x) >> 24)       )
+#define red(x)         (((x) >> 16) & 0xff)
+#define green(x)       (((x) >>  8) & 0xff)
+#define blue(x)                (((x)      ) & 0xff)
+#define all(OP,A,R,G,B,W,I)                             \
+                do {                                    \
+                        A OP alpha(I) * W;              \
+                        R OP red(I) * W;                \
+                        G OP green(I) * W;              \
+                        B OP blue(I) * W;               \
+                } while (0)
+#define wavg(x,n)        (((x) / (n)) & 0xff)
+#define wavgd(x,n)        ((uint32_t)((x) / (n)) & 0xff)
+
+typedef int (*FilterH)(int, uint32_t *, int, uint32_t *);
+typedef int (*FilterV)(int, uint32_t *, int, int, uint32_t *);
+int gaussian_filter_h(int rad, uint32_t *in, int w, uint32_t *out);
+int gaussian_filter_h64(int rad, uint32_t *in, int w, uint32_t *out);
+int gaussian_filter_hd(int rad, uint32_t *in, int w, uint32_t *out);
+int gaussian_filter_v(int rad, uint32_t *in, int h, int skip, uint32_t *out);
+int gaussian_filter_v64(int rad, uint32_t *in, int h, int skip, uint32_t *out);
+int gaussian_filter_vd(int rad, uint32_t *in, int h, int skip, uint32_t *out);
+const uint32_t *gaussian_row_get(int row, int *npoints, uint32_t *weight);
+const uint64_t *gaussian_row_get64(int row, int *npoints, uint64_t *weight);
+const double *gaussian_row_getd(int row, int *npoints, double *weight);
+
+
+Eina_Bool
+gaussian_filter(Evas_Filter_Info *filter, RGBA_Image *src, RGBA_Image *dst)
+{
+   int i;
+   uint32_t nw, nh;
+   uint32_t *in, *tmp, *out;
+   FilterV filter_v = gaussian_filter_v;
+   FilterH filter_h = gaussian_filter_h;
+   Evas_Filter_Info_Blur *blur;
+   int w,h;
+
+   blur = filter->data;
+
+   printf("Gaussian filter\n");
+   /* Use 64 bit version if we are going to overflow */
+   if (blur->radius > 508){ /** too big for doubles: Bail out */
+        return EINA_FALSE;
+   } else if (blur->radius > 28){
+        filter_v = gaussian_filter_vd;
+        filter_h = gaussian_filter_hd;
+   } else if (blur->radius > 12){
+        filter_v = gaussian_filter_v64;
+        filter_h = gaussian_filter_h64;
+   }
+
+   w = src->cache_entry.w;
+   h = src->cache_entry.h;
+   in = src->image.data;
+
+   if (!in) return EINA_FALSE;
+
+   nw = w + 2 * blur->radius;
+   nh = h + 2 * blur->radius;
+
+   out = dst->image.data;
+   if (!out) return EINA_FALSE;
+   tmp = malloc(nw * h * sizeof(uint32_t));
+
+   for (i = 0 ; i < h ; i ++)
+      filter_h(blur->radius,in + i*w,w,tmp + i*nw);
+
+   for (i = 0 ; i < nw ; i ++)
+      filter_v(blur->radius,tmp + i,h,nw,out + i);
+
+   free(tmp);
+   return EINA_TRUE;
+}
+
+/* Blur only horizontally */
+int
+gaussian_filter_h(int rad, uint32_t *in, int w, uint32_t *out){
+       const uint32_t *points;
+       int npoints;
+       uint32_t weight;
+        int i,k;
+       uint32_t r,g,b,a;
+
+       /* Get twice the radius: even rows have 1 element */
+       points = gaussian_row_get(rad * 2,&npoints, &weight);
+
+       for (i = -rad ; i < w + rad; i ++){
+               r = g = b = a = 0;
+               for (k = -rad ; k <= rad ; k ++){
+                       if ((k + i) < 0) continue;
+                       if ((k + i) >= w) continue;
+                       all(+=, a, r, g, b, points[k + rad], in[k + i]);
+               }
+               *(out) = (wavg(a,weight) << 24) |
+                        (wavg(r,weight) << 16) |
+                        (wavg(g,weight) <<  8) |
+                        (wavg(b,weight));
+               out ++;
+       }
+
+       return 0;
+}
+
+/* Blur only horizontally */
+int
+gaussian_filter_hd(int rad, uint32_t *in, int w, uint32_t *out){
+       const double *points;
+       int npoints;
+       double weight;
+        int i,k;
+       double r,g,b,a;
+
+       /* Get twice the radius: even rows have 1 element */
+       points = gaussian_row_getd(rad * 2,&npoints, &weight);
+
+       for (i = -rad ; i < w + rad; i ++){
+               r = g = b = a = 0;
+               for (k = -rad ; k <= rad ; k ++){
+                       if ((k + i) < 0) continue;
+                       if ((k + i) >= w) continue;
+                       all(+=, a, r, g, b, points[k + rad], in[k + i]);
+               }
+               *(out) = (wavgd(a,weight) << 24) |
+                        (wavgd(r,weight) << 16) |
+                        (wavgd(g,weight) <<  8) |
+                        (wavgd(b,weight));
+               out ++;
+       }
+
+       return 0;
+}
+
+
+/* Blur only horizontally */
+int
+gaussian_filter_h64(int rad, uint32_t *in, int w, uint32_t *out){
+       const uint64_t *points;
+       int npoints;
+       uint64_t weight;
+        int i,k;
+       uint64_t r,g,b,a;
+
+       /* Get twice the radius: even rows have 1 element */
+       points = gaussian_row_get64(rad * 2,&npoints, &weight);
+
+       for (i = -rad ; i < w + rad; i ++){
+               r = g = b = a = 0;
+               for (k = -rad ; k <= rad ; k ++){
+                       if ((k + i) < 0) continue;
+                       if ((k + i) >= w) continue;
+                       all(+=, a, r, g, b, points[k + rad], in[k + i]);
+               }
+               *(out) = (wavg(a,weight) << 24) |
+                        (wavg(r,weight) << 16) |
+                        (wavg(g,weight) <<  8) |
+                        (wavg(b,weight));
+               out ++;
+       }
+
+       return 0;
+}
+
+
+
+int
+gaussian_filter_v(int rad, uint32_t *in, int h, int skip, uint32_t *out){
+       const uint32_t *points;
+       int npoints;
+       uint32_t weight;
+        int i,k;
+       uint32_t r,g,b,a;
+
+       /* Get twice the radius: even rows have 1 element */
+       points = gaussian_row_get(rad * 2,&npoints, &weight);
+       weight = 0;
+       for (i = 0 ; i < npoints ; i ++)
+               weight += points[i];
+
+       for (i = -rad ; i < h + rad; i ++){
+               r = g = b = a = 0;
+               for (k = -rad ; k <= rad ; k ++){
+                       if ((k + i) < 0) continue;
+                       if ((k + i) >= h) continue;
+                       all(+=, a, r, g, b, points[k + rad],
+                                       in[skip * (k + i)]);
+               }
+               *(out) = (wavg(a,weight) << 24) |
+                        (wavg(r,weight) << 16) |
+                        (wavg(g,weight) <<  8) |
+                        (wavg(b,weight));
+               out += skip;
+       }
+
+       return 0;
+}
+
+int
+gaussian_filter_v64(int rad, uint32_t *in, int h, int skip, uint32_t *out){
+       const uint64_t *points;
+       int npoints;
+       uint64_t weight;
+        int i,k;
+       uint64_t r,g,b,a;
+
+       /* Get twice the radius: even rows have 1 element */
+       points = gaussian_row_get64(rad * 2,&npoints, &weight);
+       weight = 0;
+       for (i = 0 ; i < npoints ; i ++)
+               weight += points[i];
+
+       for (i = -rad ; i < h + rad; i ++){
+               r = g = b = a = 0;
+               for (k = -rad ; k <= rad ; k ++){
+                       if ((k + i) < 0) continue;
+                       if ((k + i) >= h) continue;
+                       all(+=, a, r, g, b, points[k + rad],
+                                       in[skip * (k + i)]);
+               }
+               *(out) = (wavg(a,weight) << 24) |
+                        (wavg(r,weight) << 16) |
+                        (wavg(g,weight) <<  8) |
+                        (wavg(b,weight));
+               out += skip;
+       }
+
+       return 0;
+}
+
+
+int
+gaussian_filter_vd(int rad, uint32_t *in, int h, int skip, uint32_t *out){
+       const double *points;
+       int npoints;
+       double weight;
+        int i,k;
+       double r,g,b,a;
+
+       /* Get twice the radius: even rows have 1 element */
+       points = gaussian_row_getd(rad * 2,&npoints, &weight);
+       weight = 0;
+       for (i = 0 ; i < npoints ; i ++)
+               weight += points[i];
+
+       for (i = -rad ; i < h + rad; i ++){
+               r = g = b = a = 0;
+               for (k = -rad ; k <= rad ; k ++){
+                       if ((k + i) < 0) continue;
+                       if ((k + i) >= h) continue;
+                       all(+=, a, r, g, b, points[k + rad],
+                                       in[skip * (k + i)]);
+               }
+               *(out) = (wavgd(a,weight) << 24) |
+                        (wavgd(r,weight) << 16) |
+                        (wavgd(g,weight) <<  8) |
+                        (wavgd(b,weight));
+               out += skip;
+       }
+
+       return 0;
+}
+
+
+const uint32_t *
+gaussian_row_get(int row, int *npoints, uint32_t *weight){
+       static uint32_t *points = NULL;
+       static int last = -1;
+       static uint32_t lastweight = -1;
+       int c,k;
+
+       if (row < 0) return NULL;
+
+       if (npoints) *npoints = row + 1;
+
+       if (last == row){
+               if (weight) *weight = lastweight;
+               return points;
+       }
+       if (points) free(points);
+
+       points = malloc((row + 1) * sizeof(uint32_t));
+       if (!points){
+               last = -1;
+               return NULL;
+       }
+       last = row;
+
+
+       c = 1;
+       for (k = 0 ; k <= row ; k ++){
+               points[k] = c;
+               c = c * (row-k)/(k+1);
+       }
+
+       for (k = 0, lastweight = 0 ; k <= row ; k ++)
+               lastweight += points[k];
+
+       if (weight) *weight = lastweight;
+
+       return points;
+}
+
+const uint64_t *
+gaussian_row_get64(int row, int *npoints, uint64_t *weight){
+       static uint64_t *points = NULL;
+       static int last = -1;
+       static uint64_t lastweight = -1;
+       uint64_t c;
+       int k;
+
+       if (row < 0) return NULL;
+
+       if (npoints) *npoints = row + 1;
+       if (last == row){
+               if (weight) *weight = lastweight;
+               return points;
+       }
+        if (points) free(points);
+
+       points = malloc((row + 1) * sizeof(uint64_t));
+       if (!points){
+               last = -1;
+               return NULL;
+       }
+       last = row;
+
+
+       c = 1;
+       for (k = 0 ; k <= row ; k ++){
+               points[k] = c;
+               c = c * (row-k)/(k+1);
+       }
+
+       for (k = 0, lastweight = 0 ; k <= row ; k ++)
+               lastweight += points[k];
+
+       if (weight) *weight = lastweight;
+
+       return points;
+}
+const double *
+gaussian_row_getd(int row, int *npoints, double *weight){
+       static double *points = NULL;
+       static int last = -1;
+       static double lastweight = -1;
+       double c;
+       int k;
+
+       if (row < 0) return NULL;
+
+       if (last == row){
+               if (weight) *weight = lastweight;
+               return points;
+       }
+
+        if (points) free(points);
+       points = malloc((row + 1) * sizeof(double));
+       if (!points){
+               last = -1;
+               return NULL;
+       }
+       last = row;
+
+       if (npoints) *npoints = row + 1;
+
+       c = 1;
+       for (k = 0 ; k <= row ; k ++){
+               points[k] = c;
+               c = c * (row-k)/(k+1);
+       }
+
+       for (k = 0, lastweight = 0 ; k <= row ; k ++)
+               lastweight += points[k];
+
+       if (weight) *weight = lastweight;
+
+       return points;
+}
+
+
+
+static Eina_Bool
+negation_filter(Evas_Filter_Info *info, RGBA_Image *src, RGBA_Image *dst)
+{
+   uint32_t *in, *out;
+   int i,j;
+   int w,h;
+   uint32_t mask,a;
+
+   if (BUILD_NEON0 && evas_common_cpu_has_feature(CPU_FEATURE_NEON))
+      return negation_filter_neon(info, src, dst);
+
+   in = src->image.data;
+   out = dst->image.data;
+   w = src->cache_entry.w;
+   h = src->cache_entry.h;
+
+   if (src->cache_entry.flags.alpha)
+     {
+        for (i = 0 ; i < h ; i ++)
+          {
+             for (j = 0 ; j < w ; j ++)
+               {
+                  a = (*in >> 24) & 0xff;
+                  mask = a | (a << 8) | (a << 16);
+                  *out = (mask - (*in & 0xffffff)) | (a << 24);
+                  out ++;
+                  in ++;
+               }
+          }
+
+     }
+   else
+     {
+        for (i = 0 ; i < h ; i ++)
+          {
+             for (j = 0 ; j < w ; j ++)
+               {
+                  *out = ~(*in & ~0xff000000) | ((*in) & 0xff000000);
+                  out ++;
+                  in ++;
+               }
+          }
+     }
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+negation_filter_neon(Evas_Filter_Info *info, RGBA_Image *src, RGBA_Image *dst)
+{
+#if BUILD_NEON0
+   uint32_t tmp;
+
+   if (src->cache_entry.flags.alpha)
+     {
+
+     }
+   else
+     {
+        /* No alpha */
+#define AP  "NEG_FILTER_NA"
+        asm volatile (
+
+           ".fpu neon                                       \n\t"
+           "vdup.u32    q14,   $0xff000000                   \n\t"
+           "vmvn.u32    q15,   q1                            \n\t"
+
+           // fixme: do check for small loops
+           AP"loopinit:                                     \n\t"
+               "sub     %[tmp], %[e], #31                   \n\t"
+
+           AP"loop:                                         \n\t"
+               "vldm    %[s]!,    {d0,d1,d2,d3}             \n\t"
+               "vand    q2,   q0, q15                       \n\t"
+               "vand    q3,   q1, q15                       \n\t"
+               "vand    q4,   q0, q14                       \n\t"
+               "vand    q5,   q1, q14                       \n\t"
+                        // fixme: can i do this with xor
+               "cmp     %[tmp], %[s]                        \n\t"
+
+               "vmvn    q6,   q2                            \n\t"
+               "vmvn    q7,   q3                            \n\t"
+
+               "vor     q0,   q6,q4                         \n\t"
+               "vor     q1,   q7,q5                         \n\t"
+
+               "vstm    %[d]1,  {d0,d1,d2,d3}               \n\t"
+
+               "bhi     "AP"loop                            \n\t"
+
+            : // no out
+            : // input
+               [e] "r" (src->image.data+ src->cache_entry.w*src->cache_entry.h),
+               [s] "r" (src->image.data),
+               [tmp] "r" (tmp),
+               [d] "r" (dst->image.data)
+            : "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7", "q14", "q15",
+                  "memory"
+         );
+#undef AP
+     }
+
+
+
+
+#endif
+   return EINA_TRUE;
+}
+
+
+
+
+
+static Eina_Bool
+sepia_filter(Evas_Filter_Info *info, RGBA_Image *src, RGBA_Image *dst)
+{
+   uint32_t *in, *out;
+   int i,j;
+   int w,h;
+   uint32_t r,g,b,nr,ng,nb;
+
+   in = src->image.data;
+   out = dst->image.data;
+   w = src->cache_entry.w;
+   h = src->cache_entry.h;
+
+   for (i = 0 ; i < h ; i ++)
+     {
+        for (j = 0; j < w ; j ++)
+          {
+             r = R_VAL(in);
+             g = G_VAL(in);
+             b = B_VAL(in);
+             nr = ((uint32_t)((r * .393) + (g *.769) + (b * .189)));
+             ng = ((uint32_t)((r * .349) + (g *.686) + (b * .168)));
+             nb = ((uint32_t)((r * .272) + (g *.534) + (b * .131)));
+             if (nr > 255) nr = 255;
+             if (ng > 255) ng = 255;
+             if (nb > 255) nb = 255;
+             *out = (*in & 0xff000000) | (nr << 16) | (ng << 8) | nb;
+             out ++;
+             in ++;
+          }
+     }
+
+   return EINA_TRUE;
+
+}
+static Eina_Bool
+greyscale_filter(Evas_Filter_Info *info, RGBA_Image *src, RGBA_Image *dst)
+{
+   uint32_t *in, *out;
+   int i,j;
+   int w,h;
+   uint32_t cur;
+   uint32_t a, r,g,b;
+
+   in = src->image.data;
+   out = dst->image.data;
+   w = src->cache_entry.w;
+   h = src->cache_entry.h;
+
+   if (src->cache_entry.flags.alpha)
+     {
+        for (i = 0 ; i < h ; i ++)
+          {
+             for (j = 0; j < w ; j ++)
+               {
+                  a = A_VAL(in);
+                  r = R_VAL(in);
+                  g = G_VAL(in);
+                  b = B_VAL(in);
+                  cur = r * 0.3 + g * 0.59 + b * 0.11;
+                  cur |= cur << 16;
+                  *out = (a << 24) | cur | (cur << 8);
+                  out ++;
+                  in ++;
+               }
+          }
+     }
+   else
+     {
+        for (i = 0 ; i < h ; i ++)
+          {
+             for (j = 0; j < w ; j ++)
+               {
+                  r = R_VAL(in);
+                  g = G_VAL(in);
+                  b = B_VAL(in);
+                  cur = r * 0.3 + g * 0.59 + b * 0.11;
+                  cur |= cur << 16;
+                  *out = 0xff000000 | cur | (cur << 8);
+                  out ++;
+                  in ++;
+               }
+          }
+     }
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+brightness_filter(Evas_Filter_Info *info, RGBA_Image *src, RGBA_Image *dst)
+{
+   uint32_t *in, *out;
+   int i,j;
+   int w,h;
+
+   in = src->image.data;
+   out = dst->image.data;
+   w = src->cache_entry.w;
+   h = src->cache_entry.h;
+
+   for (i = 0 ; i < h ; i ++)
+     {
+        for (j = 0; j < w ; j ++)
+          {
+             out ++;
+             in ++;
+          }
+     }
+
+
+   return EINA_TRUE;
+
+}
+static Eina_Bool
+contrast_filter(Evas_Filter_Info *info, RGBA_Image *src, RGBA_Image *dst)
+{
+   uint32_t *in, *out;
+   int i,j;
+   int w,h;
+
+   in = src->image.data;
+   out = dst->image.data;
+   w = src->cache_entry.w;
+   h = src->cache_entry.h;
+
+   for (i = 0 ; i < h ; i ++)
+     {
+        for (j = 0; j < w ; j ++)
+          {
+             out ++;
+             in ++;
+          }
+     }
+
+   return EINA_TRUE;
+
+}
+
+
+
+
+
+
+/* vim:set ts=8 sw=3 sts=3 expandtab cino=>5n-2f0^-2{2(0W1st0 :*/
index 9287185..e4e5d78 100644 (file)
@@ -151,6 +151,7 @@ static void
 _evas_common_rgba_image_delete(Image_Entry *ie)
 {
    RGBA_Image   *im = (RGBA_Image *) ie;
+   Filtered_Image *fi;
 
 #ifdef BUILD_PIPE_RENDER
    evas_common_pipe_free(im);
@@ -172,6 +173,14 @@ _evas_common_rgba_image_delete(Image_Entry *ie)
 #ifdef EVAS_CSERVE
    if (ie->data1) evas_cserve_image_free(ie);
 #endif   
+
+   EINA_LIST_FREE(im->filtered, fi)
+     {
+       free(fi->key);
+       _evas_common_rgba_image_delete((Image_Entry *)(fi->image));
+       free(fi);
+     }
+
    free(im);
 }
 
index 379b1ff..b3973b8 100644 (file)
@@ -519,6 +519,8 @@ typedef enum _Font_Rend_Flags
 
 /*****************************************************************************/
 
+typedef struct _Filtered_Image Filtered_Image;
+
 struct _RGBA_Image_Loadopts
 {
    int                  scale_down_by; // if > 1 then use this
@@ -803,6 +805,8 @@ struct _RGBA_Image
       Eina_Bool          dirty: 1;
    } mask;
 
+   Eina_List            *filtered;
+
    struct {
       LK(lock);
       Eina_List *list;
@@ -832,6 +836,14 @@ struct _RGBA_Map_Point
    FPc px, py, z0, foc;
 };
 
+struct _Filtered_Image
+{
+   void       *key;
+   size_t      keylen;
+   RGBA_Image *image;
+   int ref;
+};
+
 // for fonts...
 /////
 typedef struct _Fash_Item_Index_Map Fash_Item_Index_Map;
index b82881d..d9bdd89 100644 (file)
@@ -381,6 +381,30 @@ struct _Evas_Map
    Evas_Map_Point        points[]; // actual points
 };
 
+/* nash: Split into two bits */
+typedef struct Evas_Filter_Info
+{
+   Evas_Filter filter;
+   Evas_Filter_Mode mode;
+
+   Eina_Bool dirty : 1;
+
+   int datalen;
+   void *data;
+   void (*data_free)(void *);
+
+   uint8_t *key;
+   uint32_t len;
+   Filtered_Image *cached;
+} Evas_Filter_Info;
+
+typedef Eina_Bool (*Evas_Software_Filter_Fn)(Evas_Filter_Info *, RGBA_Image *, RGBA_Image *);
+
+Evas_Software_Filter_Fn evas_filter_software_get(Evas_Filter_Info *info);
+int evas_filter_get_size(Evas_Filter_Info *info, int inw, int inh,
+                     int *outw, int *outh, Eina_Bool inv);
+Eina_Bool evas_filter_always_alpha(Evas_Filter_Info *info);
+
 struct _Evas_Object
 {
    EINA_INLIST;
@@ -449,6 +473,8 @@ struct _Evas_Object
       Eina_Bool                redraw;
    } proxy;
 
+   Evas_Filter_Info           *filter;
+
    Evas_Size_Hints            *size_hints;
 
    int                         last_mouse_down_counter;
@@ -689,6 +715,11 @@ struct _Evas_Func
    Eina_Bool (*font_text_props_info_create)                (void *data __UNUSED__, void *font, const Eina_Unicode *text, Evas_Text_Props *intl_props, const Evas_BiDi_Paragraph_Props *par_props, size_t pos, size_t len);
    int  (*font_right_inset_get)                  (void *data, void *font, const Evas_Text_Props *text_props);
 
+   void (*image_draw_filtered)             (void *data, void *context, void *surface, void *image, Evas_Filter_Info *filter);
+   Filtered_Image *(*image_filtered_get)   (void *image, uint8_t *key, size_t len);
+   Filtered_Image *(*image_filtered_save)  (void *image, void *filtered, uint8_t *key, size_t len);
+   void (*image_filtered_free)             (void *image, Filtered_Image *);
+
    /* EFL-GL Glue Layer */
    void *(*gl_surface_create)            (void *data, void *config, int w, int h);
    int  (*gl_surface_destroy)            (void *data, void *surface);
index 1f95e92..e0a0fbb 100644 (file)
@@ -22,6 +22,7 @@ evas_gl_image.c \
 evas_gl_font.c \
 evas_gl_polygon.c \
 evas_gl_line.c \
+evas_gl_filter.c \
 shader/rect_frag.h \
 shader/rect_frag_bin_s3c6410.h \
 shader/rect_vert.h \
@@ -61,7 +62,25 @@ shader/tex_vert_bin_s3c6410.h \
 shader/tex_nomul_frag.h \
 shader/tex_nomul_frag_bin_s3c6410.h \
 shader/tex_nomul_vert.h \
-shader/tex_nomul_vert_bin_s3c6410.h
+shader/tex_nomul_vert_bin_s3c6410.h \
+shader/filter_invert.h \
+shader/filter_invert_nomul.h \
+shader/filter_invert_bgra.h \
+shader/filter_invert_bgra_nomul.h \
+shader/filter_sepia.h \
+shader/filter_sepia_nomul.h \
+shader/filter_sepia_bgra.h \
+shader/filter_sepia_bgra_nomul.h \
+shader/filter_greyscale.h \
+shader/filter_greyscale_nomul.h \
+shader/filter_greyscale_bgra.h \
+shader/filter_greyscale_bgra_nomul.h \
+shader/filter_blur.h \
+shader/filter_blur_nomul.h \
+shader/filter_blur_bgra.h \
+shader/filter_blur_bgra_nomul.h
+
+
 
 libevas_engine_gl_common_la_LIBADD = @EINA_LIBS@ @evas_engine_gl_common_libs@ @dlopen_libs@
 endif
@@ -96,4 +115,21 @@ shader/tex_frag.shd \
 shader/tex_frag_s3c6410.asm \
 shader/tex_vert.shd \
 shader/tex_nomul_frag.shd \
-shader/tex_nomul_vert.shd
+shader/tex_nomul_vert.shd \
+shader/filter_invert.shd \
+shader/filter_invert_nomul.shd \
+shader/filter_invert_bgra.shd \
+shader/filter_invert_bgra_nomul.shd \
+shader/filter_greyscale.shd \
+shader/filter_greyscale_nomul.shd \
+shader/filter_greyscale_bgra.shd \
+shader/filter_greyscale_bgra_nomul.shd \
+shader/filter_sepia.shd \
+shader/filter_sepia_nomul.shd \
+shader/filter_sepia_bgra.shd \
+shader/filter_sepia_bgra_nomul.shd \
+shader/filter_blur.shd \
+shader/filter_blur_nomul.shd \
+shader/filter_blur_bgra.shd \
+shader/filter_blur_bgra_nomul.shd
+
index 0318bcb..3358005 100644 (file)
@@ -196,6 +196,18 @@ struct _Evas_GL_Shared
       Evas_GL_Program  img_mask;
       Evas_GL_Program  yuv,            yuv_nomul;
       Evas_GL_Program  tex,            tex_nomul;
+
+      Evas_GL_Program  filter_invert,      filter_invert_nomul;
+      Evas_GL_Program  filter_invert_bgra, filter_invert_bgra_nomul;
+      Evas_GL_Program  filter_greyscale,      filter_greyscale_nomul;
+      Evas_GL_Program  filter_greyscale_bgra, filter_greyscale_bgra_nomul;
+      Evas_GL_Program  filter_sepia,      filter_sepia_nomul;
+      Evas_GL_Program  filter_sepia_bgra, filter_sepia_bgra_nomul;
+#if 0
+      Evas_GL_Program  filter_blur_vert;
+      Evas_GL_Program  filter_blur,      filter_blur_nomul;
+      Evas_GL_Program  filter_blur_bgra, filter_blur_bgra_nomul;
+#endif
    } shader;
    int references;
    int w, h;
@@ -285,6 +297,9 @@ struct _Evas_Engine_GL_Context
    Eina_Bool havestuff : 1;
    
    Evas_GL_Image *def_surface;
+
+   /* If this is set: Force drawing with a particular filter */
+   GLuint      filter_prog;
    
 #if defined (GLES_VARIETY_S3C6410) || defined (GLES_VARIETY_SGX)
 // FIXME: hack. expose egl display to gl core for egl image sec extn.   
@@ -357,6 +372,8 @@ struct _Evas_GL_Image
    int scale_hint, content_hint;
    int csize;
    
+   Eina_List       *filtered;
+
    unsigned char    dirty : 1;
    unsigned char    cached : 1;
    unsigned char    alpha : 1;
@@ -405,6 +422,27 @@ extern Evas_GL_Program_Source shader_tex_vert_src;
 extern Evas_GL_Program_Source shader_tex_nomul_frag_src;
 extern Evas_GL_Program_Source shader_tex_nomul_vert_src;
 
+extern Evas_GL_Program_Source shader_filter_invert_frag_src;
+extern Evas_GL_Program_Source shader_filter_invert_nomul_frag_src;
+extern Evas_GL_Program_Source shader_filter_invert_bgra_frag_src;
+extern Evas_GL_Program_Source shader_filter_invert_bgra_nomul_frag_src;
+extern Evas_GL_Program_Source shader_filter_sepia_frag_src;
+extern Evas_GL_Program_Source shader_filter_sepia_nomul_frag_src;
+extern Evas_GL_Program_Source shader_filter_sepia_bgra_frag_src;
+extern Evas_GL_Program_Source shader_filter_sepia_bgra_nomul_frag_src;
+extern Evas_GL_Program_Source shader_filter_greyscale_frag_src;
+extern Evas_GL_Program_Source shader_filter_greyscale_nomul_frag_src;
+extern Evas_GL_Program_Source shader_filter_greyscale_bgra_frag_src;
+extern Evas_GL_Program_Source shader_filter_greyscale_bgra_nomul_frag_src;
+#if 0
+/* blur (annoyingly) needs (aka is faster with) a vertex shader */
+extern Evas_GL_Program_Source shader_filter_blur_vert_src;
+extern Evas_GL_Program_Source shader_filter_blur_frag_src;
+extern Evas_GL_Program_Source shader_filter_blur_nomul_frag_src;
+extern Evas_GL_Program_Source shader_filter_blur_bgra_frag_src;
+extern Evas_GL_Program_Source shader_filter_blur_bgra_nomul_frag_src;
+#endif
+
 void glerr(int err, const char *file, const char *func, int line, const char *op);
  
 Evas_Engine_GL_Context  *evas_gl_common_context_new(void);
@@ -497,6 +535,7 @@ void              evas_gl_common_image_cache_flush(Evas_Engine_GL_Context *gc);
 void              evas_gl_common_image_free(Evas_GL_Image *im);
 Evas_GL_Image    *evas_gl_common_image_surface_new(Evas_Engine_GL_Context *gc, unsigned int w, unsigned int h, int alpha);
 void              evas_gl_common_image_dirty(Evas_GL_Image *im, unsigned int x, unsigned int y, unsigned int w, unsigned int h);
+void              evas_gl_common_image_update(Evas_Engine_GL_Context *gc, Evas_GL_Image *im);
 void              evas_gl_common_image_map_draw(Evas_Engine_GL_Context *gc, Evas_GL_Image *im, int npoints, RGBA_Map_Point *p, int smooth, int level);
 void              evas_gl_common_image_draw(Evas_Engine_GL_Context *gc, Evas_GL_Image *im, int sx, int sy, int sw, int sh, int dx, int dy, int dw, int dh, int smooth);
 
@@ -510,6 +549,12 @@ void              evas_gl_common_poly_draw(Evas_Engine_GL_Context *gc, Evas_GL_P
 
 void              evas_gl_common_line_draw(Evas_Engine_GL_Context *gc, int x1, int y1, int x2, int y2);
 
+void              evas_gl_common_filter_draw(void *data, Evas_Engine_GL_Context *context, void *image, Evas_Filter_Info *filter);
+Filtered_Image   *evas_gl_common_image_filtered_get(Evas_GL_Image *im, uint8_t *key, size_t keylen);
+Filtered_Image   *evas_gl_common_image_filtered_save(Evas_GL_Image *im, Evas_GL_Image *fimage, uint8_t *key, size_t keylen);
+void              evas_gl_common_image_filtered_free(Evas_GL_Image *im, Filtered_Image *);
+
+
 extern void (*glsym_glGenFramebuffers)      (GLsizei a, GLuint *b);
 extern void (*glsym_glBindFramebuffer)      (GLenum a, GLuint b);
 extern void (*glsym_glFramebufferTexture2D) (GLenum a, GLenum b, GLenum c, GLuint d, GLint e);
index 4b5eeae..b38d7d7 100644 (file)
@@ -470,7 +470,91 @@ _evas_gl_common_viewport_set(Evas_Engine_GL_Context *gc)
    glUniformMatrix4fv(glGetUniformLocation(gc->shared->shader.img_mask.prog, "mvp"), 1,
                       GL_FALSE, proj);
    GLERR(__FUNCTION__, __FILE__, __LINE__, "");
+   glUseProgram(gc->shared->shader.filter_invert.prog);
+   GLERR(__FUNCTION__, __FILE__, __LINE__, "");
+   glUniformMatrix4fv(glGetUniformLocation(gc->shared->shader.filter_invert.prog, "mvp"), 1,
+                      GL_FALSE, proj);
+   GLERR(__FUNCTION__, __FILE__, __LINE__, "");
+   glUseProgram(gc->shared->shader.filter_invert_nomul.prog);
+   GLERR(__FUNCTION__, __FILE__, __LINE__, "");
+   glUniformMatrix4fv(glGetUniformLocation(gc->shared->shader.filter_invert_nomul.prog, "mvp"), 1,
+                      GL_FALSE, proj);
+   GLERR(__FUNCTION__, __FILE__, __LINE__, "");
+   glUseProgram(gc->shared->shader.filter_invert_bgra.prog);
+   GLERR(__FUNCTION__, __FILE__, __LINE__, "");
+   glUniformMatrix4fv(glGetUniformLocation(gc->shared->shader.filter_invert_bgra.prog, "mvp"), 1,
+                      GL_FALSE, proj);
+   GLERR(__FUNCTION__, __FILE__, __LINE__, "");
+   glUseProgram(gc->shared->shader.filter_invert_bgra_nomul.prog);
+   GLERR(__FUNCTION__, __FILE__, __LINE__, "");
+   glUniformMatrix4fv(glGetUniformLocation(gc->shared->shader.filter_invert_bgra_nomul.prog, "mvp"), 1,
+                      GL_FALSE, proj);
+   GLERR(__FUNCTION__, __FILE__, __LINE__, "");
+
+   glUseProgram(gc->shared->shader.filter_greyscale.prog);
+   GLERR(__FUNCTION__, __FILE__, __LINE__, "");
+   glUniformMatrix4fv(glGetUniformLocation(gc->shared->shader.filter_greyscale.prog, "mvp"), 1,
+                      GL_FALSE, proj);
+   GLERR(__FUNCTION__, __FILE__, __LINE__, "");
+   glUseProgram(gc->shared->shader.filter_greyscale_nomul.prog);
+   GLERR(__FUNCTION__, __FILE__, __LINE__, "");
+   glUniformMatrix4fv(glGetUniformLocation(gc->shared->shader.filter_greyscale_nomul.prog, "mvp"), 1,
+                      GL_FALSE, proj);
+   GLERR(__FUNCTION__, __FILE__, __LINE__, "");
+   glUseProgram(gc->shared->shader.filter_greyscale_bgra.prog);
+   GLERR(__FUNCTION__, __FILE__, __LINE__, "");
+   glUniformMatrix4fv(glGetUniformLocation(gc->shared->shader.filter_greyscale_bgra.prog, "mvp"), 1,
+                      GL_FALSE, proj);
+   GLERR(__FUNCTION__, __FILE__, __LINE__, "");
+   glUseProgram(gc->shared->shader.filter_greyscale_bgra_nomul.prog);
+   GLERR(__FUNCTION__, __FILE__, __LINE__, "");
+   glUniformMatrix4fv(glGetUniformLocation(gc->shared->shader.filter_greyscale_bgra_nomul.prog, "mvp"), 1,
+                      GL_FALSE, proj);
+   GLERR(__FUNCTION__, __FILE__, __LINE__, "");
+
+   glUseProgram(gc->shared->shader.filter_sepia.prog);
+   GLERR(__FUNCTION__, __FILE__, __LINE__, "");
+   glUniformMatrix4fv(glGetUniformLocation(gc->shared->shader.filter_sepia.prog, "mvp"), 1,
+                      GL_FALSE, proj);
+   GLERR(__FUNCTION__, __FILE__, __LINE__, "");
+   glUseProgram(gc->shared->shader.filter_sepia_nomul.prog);
+   GLERR(__FUNCTION__, __FILE__, __LINE__, "");
+   glUniformMatrix4fv(glGetUniformLocation(gc->shared->shader.filter_sepia_nomul.prog, "mvp"), 1,
+                      GL_FALSE, proj);
+   GLERR(__FUNCTION__, __FILE__, __LINE__, "");
+   glUseProgram(gc->shared->shader.filter_sepia_bgra.prog);
+   GLERR(__FUNCTION__, __FILE__, __LINE__, "");
+   glUniformMatrix4fv(glGetUniformLocation(gc->shared->shader.filter_sepia_bgra.prog, "mvp"), 1,
+                      GL_FALSE, proj);
+   GLERR(__FUNCTION__, __FILE__, __LINE__, "");
+   glUseProgram(gc->shared->shader.filter_sepia_bgra_nomul.prog);
+   GLERR(__FUNCTION__, __FILE__, __LINE__, "");
+   glUniformMatrix4fv(glGetUniformLocation(gc->shared->shader.filter_sepia_bgra_nomul.prog, "mvp"), 1,
+                      GL_FALSE, proj);
+   GLERR(__FUNCTION__, __FILE__, __LINE__, "");
 
+#if 0
+   glUseProgram(gc->shared->shader.filter_blur_bgra_nomul.prog);
+   GLERR(__FUNCTION__, __FILE__, __LINE__, "");
+   glUniformMatrix4fv(glGetUniformLocation(gc->shared->shader.filter_blur_bgra_nomul.prog, "mvp"), 1,
+                      GL_FALSE, proj);
+   GLERR(__FUNCTION__, __FILE__, __LINE__, "");
+   glUseProgram(gc->shared->shader.filter_blur_bgra_nomul.prog);
+   GLERR(__FUNCTION__, __FILE__, __LINE__, "");
+   glUniformMatrix4fv(glGetUniformLocation(gc->shared->shader.filter_blur_bgra_nomul.prog, "mvp"), 1,
+                      GL_FALSE, proj);
+   GLERR(__FUNCTION__, __FILE__, __LINE__, "");
+   glUseProgram(gc->shared->shader.filter_blur_bgra_nomul.prog);
+   GLERR(__FUNCTION__, __FILE__, __LINE__, "");
+   glUniformMatrix4fv(glGetUniformLocation(gc->shared->shader.filter_blur_bgra_nomul.prog, "mvp"), 1,
+                      GL_FALSE, proj);
+   GLERR(__FUNCTION__, __FILE__, __LINE__, "");
+   glUseProgram(gc->shared->shader.filter_blur_bgra_nomul.prog);
+   GLERR(__FUNCTION__, __FILE__, __LINE__, "");
+   glUniformMatrix4fv(glGetUniformLocation(gc->shared->shader.filter_blur_bgra_nomul.prog, "mvp"), 1,
+                      GL_FALSE, proj);
+   GLERR(__FUNCTION__, __FILE__, __LINE__, "");
+#endif
 
 
    glUseProgram(gc->pipe[0].shader.cur_prog);
@@ -725,6 +809,78 @@ evas_gl_common_context_new(void)
                                                 &(shader_yuv_nomul_vert_src), 
                                                 &(shader_yuv_nomul_frag_src),
                                                 "yuv_nomul")) goto error;
+
+        /* Most of the filters use the image fragment shader */
+       if (!evas_gl_common_shader_program_init(&(shared->shader.filter_invert),
+                                               &(shader_img_vert_src),
+                                               &(shader_filter_invert_frag_src),
+                                               "filter_invert")) goto error;
+       if (!evas_gl_common_shader_program_init(&(shared->shader.filter_invert_nomul),
+                                               &(shader_img_vert_src),
+                                               &(shader_filter_invert_nomul_frag_src),
+                                               "filter_invert_nomul")) goto error;
+       if (!evas_gl_common_shader_program_init(&(shared->shader.filter_invert_bgra),
+                                               &(shader_img_vert_src),
+                                               &(shader_filter_invert_bgra_frag_src),
+                                               "filter_invert_bgra")) goto error;
+       if (!evas_gl_common_shader_program_init(&(shared->shader.filter_invert_bgra_nomul),
+                                               &(shader_img_vert_src),
+                                               &(shader_filter_invert_bgra_nomul_frag_src),
+                                               "filter_invert_bgra_nomul")) goto error;
+
+       if (!evas_gl_common_shader_program_init(&(shared->shader.filter_sepia),
+                                               &(shader_img_vert_src),
+                                               &(shader_filter_sepia_frag_src),
+                                               "filter_sepia")) goto error;
+       if (!evas_gl_common_shader_program_init(&(shared->shader.filter_sepia_nomul),
+                                               &(shader_img_vert_src),
+                                               &(shader_filter_sepia_nomul_frag_src),
+                                               "filter_sepia_nomul")) goto error;
+       if (!evas_gl_common_shader_program_init(&(shared->shader.filter_sepia_bgra),
+                                               &(shader_img_vert_src),
+                                               &(shader_filter_sepia_bgra_frag_src),
+                                               "filter_sepia_bgra")) goto error;
+       if (!evas_gl_common_shader_program_init(&(shared->shader.filter_sepia_bgra_nomul),
+                                               &(shader_img_vert_src),
+                                               &(shader_filter_sepia_bgra_nomul_frag_src),
+                                               "filter_sepia_bgra_nomul")) goto error;
+
+       if (!evas_gl_common_shader_program_init(&(shared->shader.filter_greyscale),
+                                               &(shader_img_vert_src),
+                                               &(shader_filter_greyscale_frag_src),
+                                               "filter_greyscale")) goto error;
+       if (!evas_gl_common_shader_program_init(&(shared->shader.filter_greyscale_nomul),
+                                               &(shader_img_vert_src),
+                                               &(shader_filter_greyscale_nomul_frag_src),
+                                               "filter_greyscale_nomul")) goto error;
+       if (!evas_gl_common_shader_program_init(&(shared->shader.filter_greyscale_bgra),
+                                               &(shader_img_vert_src),
+                                               &(shader_filter_greyscale_bgra_frag_src),
+                                               "filter_greyscale_bgra")) goto error;
+       if (!evas_gl_common_shader_program_init(&(shared->shader.filter_greyscale_bgra_nomul),
+                                               &(shader_img_vert_src),
+                                               &(shader_filter_greyscale_bgra_nomul_frag_src),
+                                               "filter_greyscale_bgra_nomul")) goto error;
+#if 0
+        if (!evas_gl_common_shader_program_init(&(shared->shader.filter_blur),
+                                               &(shader_filter_blur_vert_src),
+                                               &(shader_filter_blur_frag_src),
+                                               "filter_blur")) goto error;
+       if (!evas_gl_common_shader_program_init(&(shared->shader.filter_blur_nomul),
+                                               &(shader_filter_blur_vert_src),
+                                               &(shader_filter_blur_nomul_frag_src),
+                                               "filter_blur_nomul")) goto error;
+       if (!evas_gl_common_shader_program_init(&(shared->shader.filter_blur_bgra),
+                                               &(shader_filter_blur_vert_src),
+                                               &(shader_filter_blur_bgra_frag_src),
+                                               "filter_blur_bgra")) goto error;
+       if (!evas_gl_common_shader_program_init(&(shared->shader.filter_blur_bgra_nomul),
+                                               &(shader_filter_blur_vert_src),
+                                               &(shader_filter_blur_bgra_nomul_frag_src),
+                                               "filter_blur_bgra_nomul")) goto error;
+#endif
+
+
         
         glUseProgram(shared->shader.yuv.prog);
         GLERR(__FUNCTION__, __FILE__, __LINE__, "");
@@ -820,7 +976,9 @@ evas_gl_common_context_free(Evas_Engine_GL_Context *gc)
         evas_gl_common_shader_program_shutdown(&(gc->shared->shader.yuv_nomul));
         evas_gl_common_shader_program_shutdown(&(gc->shared->shader.tex));
         evas_gl_common_shader_program_shutdown(&(gc->shared->shader.tex_nomul));
-        
+
+       evas_gl_common_shader_program_shutdown(&(gc->shared->shader.filter_invert));
+
         while (gc->shared->images)
           {
              evas_gl_common_image_free(gc->shared->images->data);
@@ -1366,8 +1524,12 @@ evas_gl_common_context_image_push(Evas_Engine_GL_Context *gc,
 
    if (!tex->alpha) blend = 0;
    if (a < 255) blend = 1;
-   
-   if (tex_only)
+
+   if (gc->filter_prog)
+     {
+        prog = gc->filter_prog;
+     }
+   else if (tex_only)
      {
         if (tex->pt->dyn.img)
           {
diff --git a/src/modules/engines/gl_common/evas_gl_filter.c b/src/modules/engines/gl_common/evas_gl_filter.c
new file mode 100644 (file)
index 0000000..76d8627
--- /dev/null
@@ -0,0 +1,183 @@
+#include "evas_gl_private.h"
+
+
+void
+evas_gl_common_filter_draw(void *data, Evas_Engine_GL_Context *gc,
+               void *image, Evas_Filter_Info *filter)
+{
+   Evas_GL_Image *im = image;
+   RGBA_Draw_Context *dc;
+   GLuint prog;
+   int r,g,b,a;
+   int nomul, bgra;
+
+   dc = gc->dc;
+
+   if (dc->mul.use)
+     {
+       a = (dc->mul.col >> 24) & 0xff;
+       r = (dc->mul.col >> 16) & 0xff;
+       g = (dc->mul.col >> 8 ) & 0xff;
+       b = (dc->mul.col      ) & 0xff;
+     }
+   else
+     {
+       r = g = b = a = 255;
+     }
+
+   nomul = (a == 255 && r == 255 && g == 255 && b == 255) ? 1 : 0;
+   bgra = (gc->shared->info.bgra) ? 1 : 0;
+
+   /* FIXME: This should so be a table */
+#if 0
+   if (filter->filter == EVAS_FILTER_BLUR)
+     {
+         if (bgra)
+          {
+             if (nomul)
+                prog = gc->shared->shader.filter_blur_bgra_nomul.prog;
+             else
+                prog = gc->shared->shader.filter_blur_bgra.prog;
+          }
+        else
+          {
+             if (a == 255 && r == 255 && g == 255 && b == 255)
+                prog = gc->shared->shader.filter_blur_nomul.prog;
+             else
+                prog = gc->shared->shader.filter_blur.prog;
+          }
+     }
+   else
+#endif
+     if (filter->filter == EVAS_FILTER_INVERT)
+     {
+        if (bgra)
+          {
+             if (nomul)
+                prog = gc->shared->shader.filter_invert_bgra_nomul.prog;
+             else
+                prog = gc->shared->shader.filter_invert_bgra.prog;
+          }
+        else
+          {
+             if (a == 255 && r == 255 && g == 255 && b == 255)
+                prog = gc->shared->shader.filter_invert_nomul.prog;
+             else
+                prog = gc->shared->shader.filter_invert.prog;
+          }
+     }
+   else if (filter->filter == EVAS_FILTER_SEPIA)
+     {
+        if (bgra)
+          {
+             if (nomul)
+                prog = gc->shared->shader.filter_sepia_bgra_nomul.prog;
+             else
+                prog = gc->shared->shader.filter_sepia_bgra.prog;
+          }
+        else
+          {
+             if (nomul)
+                prog = gc->shared->shader.filter_sepia_nomul.prog;
+             else
+                prog = gc->shared->shader.filter_sepia.prog;
+          }
+
+     }
+   else /*if (filter->filter == EVAS_FILTER_GREYSCALE)*/
+     {
+        printf("BGRA: %s  Nomul: %s\n",bgra?"true":"false",nomul?"nomul":"mul");
+        if (bgra)
+          {
+             if (nomul)
+                prog = gc->shared->shader.filter_greyscale_bgra_nomul.prog;
+             else
+                prog = gc->shared->shader.filter_greyscale_bgra.prog;
+          }
+        else
+          {
+             if (nomul)
+                prog = gc->shared->shader.filter_greyscale_nomul.prog;
+             else
+                prog = gc->shared->shader.filter_greyscale.prog;
+          }
+
+     }
+
+   printf("Prog: %d %d %d\n",prog,im->w,im->h);
+   gc->filter_prog = prog;
+   evas_gl_common_image_update(gc, im);
+   evas_gl_common_context_image_push(gc, im->tex, 0, 0, im->w, im->h,
+                                      0, 0, im->w, im->h,
+                                      r,g,b,a,
+                                      1, im->tex_only);
+   gc->filter_prog = 0;
+}
+
+
+Filtered_Image *
+evas_gl_common_image_filtered_get(Evas_GL_Image *im, uint8_t *key, size_t len)
+{
+   Filtered_Image *fi;
+   Eina_List *l;
+
+   for (l = im->filtered ; l ; l = l->next)
+     {
+         fi = l->data;
+         if (fi->keylen != len) continue;
+         if (memcmp(key, fi->key, len) != 0) continue;
+         fi->ref ++;
+         return fi;
+     }
+
+   return NULL;
+}
+
+Filtered_Image *
+evas_gl_common_image_filtered_save(Evas_GL_Image *im, Evas_GL_Image *fimage,
+                                   uint8_t *key, size_t keylen)
+{
+   Filtered_Image *fi;
+   Eina_List *l;
+
+   for (l = im->filtered ; l ; l = l->next)
+     {
+        fi = l->data;
+        if (fi->keylen != keylen) continue;
+        if (memcmp(key, fi->key, keylen) != 0) continue;
+
+        fi->image = (void *)fimage;
+        fi->ref ++;
+        return fi;
+     }
+
+   fi = calloc(1,sizeof(Filtered_Image));
+   if (!fi) return NULL;
+
+   fi->keylen = keylen;
+   fi->key = malloc(keylen);
+   memcpy(fi->key, key, keylen);
+   fi->image = (void *)fimage;
+   fi->ref = 1;
+
+   im->filtered = eina_list_prepend(im->filtered, fi);
+
+   return fi;
+}
+
+void
+evas_gl_common_image_filtered_free(Evas_GL_Image *image, Filtered_Image *fi)
+{
+   fi->ref --;
+   if (fi->ref) return;
+
+   free(fi->key);
+   evas_gl_common_image_free((void *)fi->image);
+   fi->image = NULL;
+
+   image->filtered = eina_list_remove(image->filtered, fi);
+}
+
+
+
+/* vim:set ts=8 sw=3 sts=3 expandtab cino=>5n-2f0^-2{2(0W1st0 :*/
index 30297ef..7f10441 100644 (file)
@@ -433,6 +433,9 @@ evas_gl_common_image_cache_flush(Evas_Engine_GL_Context *gc)
 void
 evas_gl_common_image_free(Evas_GL_Image *im)
 {
+   Filtered_Image *fi;
+
+   evas_gl_common_context_flush(im->gc);
    im->references--;
    if (im->references > 0) return;
    
@@ -449,6 +452,15 @@ evas_gl_common_image_free(Evas_GL_Image *im)
      }
    if (im->im) evas_cache_image_drop(&im->im->cache_entry);
    if (im->tex) evas_gl_common_texture_free(im->tex);
+
+   EINA_LIST_FREE(im->filtered, fi)
+     {
+       free(fi->key);
+       evas_gl_common_image_free((Evas_GL_Image *)fi->image);
+       free(fi);
+     }
+
+
    free(im);
 }
 
@@ -485,8 +497,8 @@ evas_gl_common_image_dirty(Evas_GL_Image *im, unsigned int x, unsigned int y, un
    im->dirty = 1;
 }
 
-static void
-_evas_gl_common_image_update(Evas_Engine_GL_Context *gc, Evas_GL_Image *im)
+void
+evas_gl_common_image_update(Evas_Engine_GL_Context *gc, Evas_GL_Image *im)
 {
    if (!im->im) return;
 /*   
@@ -574,7 +586,7 @@ evas_gl_common_image_map_draw(Evas_Engine_GL_Context *gc, Evas_GL_Image *im,
         r = g = b = a = 255;
      }
    
-   _evas_gl_common_image_update(gc, im);
+   evas_gl_common_image_update(gc, im);
 
    c = gc->dc->clip.use; 
    cx = gc->dc->clip.x; cy = gc->dc->clip.y; 
@@ -616,7 +628,7 @@ evas_gl_common_image_draw(Evas_Engine_GL_Context *gc, Evas_GL_Image *im, int sx,
        r = g = b = a = 255;
      }
    
-   _evas_gl_common_image_update(gc, im);
+   evas_gl_common_image_update(gc, im);
    if (!im->tex)
      {
         evas_gl_common_rect_draw(gc, dx, dy, dw, dh);
index 1b89aa3..2a5c69e 100644 (file)
@@ -443,6 +443,167 @@ Evas_GL_Program_Source shader_img_bgra_nomul_vert_src =
 };
 
 /////////////////////////////////////////////
+const char filter_invert_frag_glsl[] =
+#include "shader/filter_invert.h"
+  ;
+Evas_GL_Program_Source shader_filter_invert_frag_src =
+{
+   filter_invert_frag_glsl,
+   NULL, 0
+};
+
+const char filter_invert_nomul_frag_glsl[] =
+#include "shader/filter_invert_nomul.h"
+  ;
+Evas_GL_Program_Source shader_filter_invert_nomul_frag_src =
+{
+   filter_invert_nomul_frag_glsl,
+   NULL, 0
+};
+
+const char filter_invert_bgra_frag_glsl[] =
+#include "shader/filter_invert_bgra.h"
+  ;
+Evas_GL_Program_Source shader_filter_invert_bgra_frag_src =
+{
+   filter_invert_bgra_frag_glsl,
+   NULL, 0
+};
+const char filter_invert_bgra_nomul_frag_glsl[] =
+#include "shader/filter_invert_bgra_nomul.h"
+  ;
+Evas_GL_Program_Source shader_filter_invert_bgra_nomul_frag_src =
+{
+   filter_invert_bgra_nomul_frag_glsl,
+   NULL, 0
+};
+
+/////////////////////////////////////////////
+const char filter_greyscale_frag_glsl[] =
+#include "shader/filter_greyscale.h"
+  ;
+Evas_GL_Program_Source shader_filter_greyscale_frag_src =
+{
+   filter_greyscale_frag_glsl,
+   NULL, 0
+};
+
+const char filter_greyscale_nomul_frag_glsl[] =
+#include "shader/filter_greyscale_nomul.h"
+  ;
+Evas_GL_Program_Source shader_filter_greyscale_nomul_frag_src =
+{
+   filter_greyscale_nomul_frag_glsl,
+   NULL, 0
+};
+
+const char filter_greyscale_bgra_frag_glsl[] =
+#include "shader/filter_greyscale_bgra.h"
+  ;
+Evas_GL_Program_Source shader_filter_greyscale_bgra_frag_src =
+{
+   filter_greyscale_bgra_frag_glsl,
+   NULL, 0
+};
+const char filter_greyscale_bgra_nomul_frag_glsl[] =
+#include "shader/filter_greyscale_bgra_nomul.h"
+  ;
+Evas_GL_Program_Source shader_filter_greyscale_bgra_nomul_frag_src =
+{
+   filter_greyscale_bgra_nomul_frag_glsl,
+   NULL, 0
+};
+
+/////////////////////////////////////////////
+const char filter_sepia_frag_glsl[] =
+#include "shader/filter_sepia.h"
+  ;
+Evas_GL_Program_Source shader_filter_sepia_frag_src =
+{
+   filter_sepia_frag_glsl,
+   NULL, 0
+};
+
+const char filter_sepia_nomul_frag_glsl[] =
+#include "shader/filter_sepia_nomul.h"
+  ;
+Evas_GL_Program_Source shader_filter_sepia_nomul_frag_src =
+{
+   filter_sepia_nomul_frag_glsl,
+   NULL, 0
+};
+
+const char filter_sepia_bgra_frag_glsl[] =
+#include "shader/filter_sepia_bgra.h"
+  ;
+Evas_GL_Program_Source shader_filter_sepia_bgra_frag_src =
+{
+   filter_sepia_bgra_frag_glsl,
+   NULL, 0
+};
+const char filter_sepia_bgra_nomul_frag_glsl[] =
+#include "shader/filter_sepia_bgra_nomul.h"
+  ;
+Evas_GL_Program_Source shader_filter_sepia_bgra_nomul_frag_src =
+{
+   filter_sepia_bgra_nomul_frag_glsl,
+   NULL, 0
+};
+
+/////////////////////////////////////////////
+#if 0
+       Blur is a work in progress currently.
+       Mostly because GPUs are so hopeless.
+const char filter_blur_vert_glsl[] =
+#include "shader/filter_blur_vert.h"
+  ;
+
+Evas_GL_Program_Source shader_filter_blur_vert_src =
+{
+   filter_blur_vert_glsl,
+   NULL, 0
+};
+
+const char filter_blur_frag_glsl[] =
+#include "shader/filter_blur.h"
+  ;
+Evas_GL_Program_Source shader_filter_blur_frag_src =
+{
+   filter_blur_frag_glsl,
+   NULL, 0
+};
+
+const char filter_blur_nomul_frag_glsl[] =
+#include "shader/filter_blur_nomul.h"
+  ;
+Evas_GL_Program_Source shader_filter_blur_nomul_frag_src =
+{
+   filter_blur_nomul_frag_glsl,
+   NULL, 0
+};
+
+const char filter_blur_bgra_frag_glsl[] =
+#include "shader/filter_blur_bgra.h"
+  ;
+Evas_GL_Program_Source shader_filter_blur_bgra_frag_src =
+{
+   filter_blur_bgra_frag_glsl,
+   NULL, 0
+};
+const char filter_blur_bgra_nomul_frag_glsl[] =
+#include "shader/filter_blur_bgra_nomul.h"
+  ;
+Evas_GL_Program_Source shader_filter_blur_bgra_nomul_frag_src =
+{
+   filter_blur_bgra_nomul_frag_glsl,
+   NULL, 0
+};
+
+#endif
+
+
+
+/////////////////////////////////////////////
 static void
 gl_compile_link_error(GLuint target, const char *action)
 {
diff --git a/src/modules/engines/gl_common/shader/filter_blur.h b/src/modules/engines/gl_common/shader/filter_blur.h
new file mode 100644 (file)
index 0000000..69e8c07
--- /dev/null
@@ -0,0 +1,20 @@
+"#ifdef GL_ES\n"
+"precision mediump float;\n"
+"#endif\n"
+"uniform sampler2D tex;\n"
+"uniform sampler1D gaussian;\n"
+"varying vec4 col;\n"
+"varying vec2 tex_c;\n"
+"varying weight;\n"
+"uniform radius;\n"
+"void main()\n"
+"{\n"
+"      int i;\n"
+"      vec4 fc = vec4(0,0,0,0);\n"
+"      \n"
+"      for (i = 0 ; i < radius ; i ++){\n"
+"              fc += texture2D(tex, tex_c.xy).rgba *\n"
+"                      texture1D(gaussian,i/radius).aaaa;\n"
+"      }\n"
+"      gl_FragColor = fc / 4 * col;\n"
+"}\n"
diff --git a/src/modules/engines/gl_common/shader/filter_blur.shd b/src/modules/engines/gl_common/shader/filter_blur.shd
new file mode 100644 (file)
index 0000000..59b5809
--- /dev/null
@@ -0,0 +1,20 @@
+#ifdef GL_ES
+precision mediump float;
+#endif
+uniform sampler2D tex;
+uniform sampler1D gaussian;
+varying vec4 col;
+varying vec2 tex_c;
+varying weight;
+uniform radius;
+void main()
+{
+       int i;
+       vec4 fc = vec4(0,0,0,0);
+       
+       for (i = 0 ; i < radius ; i ++){
+               fc += texture2D(tex, tex_c.xy).rgba *
+                       texture1D(gaussian,i/radius).aaaa;
+       }
+       gl_FragColor = fc / 4 * col;
+}
diff --git a/src/modules/engines/gl_common/shader/filter_blur_bgra.h b/src/modules/engines/gl_common/shader/filter_blur_bgra.h
new file mode 100644 (file)
index 0000000..4dc5f37
--- /dev/null
@@ -0,0 +1,20 @@
+"#ifdef GL_ES\n"
+"precision mediump float;\n"
+"#endif\n"
+"uniform sampler2D tex;\n"
+"uniform sampler1D gaussian;\n"
+"varying vec4 col;\n"
+"varying vec2 tex_c;\n"
+"varying weight;\n"
+"uniform radius;\n"
+"void main()\n"
+"{\n"
+"      int i;\n"
+"      vec4 fc = vec4(0,0,0,0);\n"
+"      \n"
+"      for (i = 0 ; i < radius ; i ++){\n"
+"              fc += texture2D(tex, tex_c.xy).rgba *\n"
+"                      texture1D(gaussian,i/radius).aaaa;\n"
+"      }\n"
+"      gl_FragColor = fc / 4;\n"
+"}\n"
diff --git a/src/modules/engines/gl_common/shader/filter_blur_bgra.shd b/src/modules/engines/gl_common/shader/filter_blur_bgra.shd
new file mode 100644 (file)
index 0000000..efd7932
--- /dev/null
@@ -0,0 +1,20 @@
+#ifdef GL_ES
+precision mediump float;
+#endif
+uniform sampler2D tex;
+uniform sampler1D gaussian;
+varying vec4 col;
+varying vec2 tex_c;
+varying weight;
+uniform radius;
+void main()
+{
+       int i;
+       vec4 fc = vec4(0,0,0,0);
+       
+       for (i = 0 ; i < radius ; i ++){
+               fc += texture2D(tex, tex_c.xy).rgba *
+                       texture1D(gaussian,i/radius).aaaa;
+       }
+       gl_FragColor = fc / 4;
+}
diff --git a/src/modules/engines/gl_common/shader/filter_blur_bgra_nomul.h b/src/modules/engines/gl_common/shader/filter_blur_bgra_nomul.h
new file mode 100644 (file)
index 0000000..4dc5f37
--- /dev/null
@@ -0,0 +1,20 @@
+"#ifdef GL_ES\n"
+"precision mediump float;\n"
+"#endif\n"
+"uniform sampler2D tex;\n"
+"uniform sampler1D gaussian;\n"
+"varying vec4 col;\n"
+"varying vec2 tex_c;\n"
+"varying weight;\n"
+"uniform radius;\n"
+"void main()\n"
+"{\n"
+"      int i;\n"
+"      vec4 fc = vec4(0,0,0,0);\n"
+"      \n"
+"      for (i = 0 ; i < radius ; i ++){\n"
+"              fc += texture2D(tex, tex_c.xy).rgba *\n"
+"                      texture1D(gaussian,i/radius).aaaa;\n"
+"      }\n"
+"      gl_FragColor = fc / 4;\n"
+"}\n"
diff --git a/src/modules/engines/gl_common/shader/filter_blur_bgra_nomul.shd b/src/modules/engines/gl_common/shader/filter_blur_bgra_nomul.shd
new file mode 100644 (file)
index 0000000..efd7932
--- /dev/null
@@ -0,0 +1,20 @@
+#ifdef GL_ES
+precision mediump float;
+#endif
+uniform sampler2D tex;
+uniform sampler1D gaussian;
+varying vec4 col;
+varying vec2 tex_c;
+varying weight;
+uniform radius;
+void main()
+{
+       int i;
+       vec4 fc = vec4(0,0,0,0);
+       
+       for (i = 0 ; i < radius ; i ++){
+               fc += texture2D(tex, tex_c.xy).rgba *
+                       texture1D(gaussian,i/radius).aaaa;
+       }
+       gl_FragColor = fc / 4;
+}
diff --git a/src/modules/engines/gl_common/shader/filter_blur_nomul.h b/src/modules/engines/gl_common/shader/filter_blur_nomul.h
new file mode 100644 (file)
index 0000000..4dc5f37
--- /dev/null
@@ -0,0 +1,20 @@
+"#ifdef GL_ES\n"
+"precision mediump float;\n"
+"#endif\n"
+"uniform sampler2D tex;\n"
+"uniform sampler1D gaussian;\n"
+"varying vec4 col;\n"
+"varying vec2 tex_c;\n"
+"varying weight;\n"
+"uniform radius;\n"
+"void main()\n"
+"{\n"
+"      int i;\n"
+"      vec4 fc = vec4(0,0,0,0);\n"
+"      \n"
+"      for (i = 0 ; i < radius ; i ++){\n"
+"              fc += texture2D(tex, tex_c.xy).rgba *\n"
+"                      texture1D(gaussian,i/radius).aaaa;\n"
+"      }\n"
+"      gl_FragColor = fc / 4;\n"
+"}\n"
diff --git a/src/modules/engines/gl_common/shader/filter_blur_nomul.shd b/src/modules/engines/gl_common/shader/filter_blur_nomul.shd
new file mode 100644 (file)
index 0000000..efd7932
--- /dev/null
@@ -0,0 +1,20 @@
+#ifdef GL_ES
+precision mediump float;
+#endif
+uniform sampler2D tex;
+uniform sampler1D gaussian;
+varying vec4 col;
+varying vec2 tex_c;
+varying weight;
+uniform radius;
+void main()
+{
+       int i;
+       vec4 fc = vec4(0,0,0,0);
+       
+       for (i = 0 ; i < radius ; i ++){
+               fc += texture2D(tex, tex_c.xy).rgba *
+                       texture1D(gaussian,i/radius).aaaa;
+       }
+       gl_FragColor = fc / 4;
+}
diff --git a/src/modules/engines/gl_common/shader/filter_blur_vert.h b/src/modules/engines/gl_common/shader/filter_blur_vert.h
new file mode 100644 (file)
index 0000000..80fd733
--- /dev/null
@@ -0,0 +1,29 @@
+"#ifdef GL_ES\n"
+"precision mediump float;\n"
+"#endif\n"
+"attribute vec4 vertex;\n"
+"attribute vec4 color;\n"
+"attribute vec2 tex_coord;\n"
+"attribute float r;\n"
+"uniform mat4 mvp;\n"
+"uniform sampler1D tex_blur;\n"
+"varying float weight;\n"
+"varying vec4 col;\n"
+"varying vec2 tex_c;\n"
+"\n"
+"void main(){\n"
+"      /* FIXME: This index shoudl be tweaked so for \n"
+"              radius 1, I want 3 points at 1/4, 2/4, 3/4 */\n"
+"      /*\n"
+"      for (float i = 0 ; i <= radius * 2 ; i ++){\n"
+"              float pos = i;\n"
+"              float r = float(radius);\n"
+"              weight += sampler1D(tex_blur, 1.0 / (r * 2.0 * pos));\n"
+"      }*/\n"
+"      for (float i = 0.0 ; i < r * 2.0 ; i += 1.0){\n"
+"              weight += sampler1D(tex_blur, 1.0 / (r * 2.0 * i));\n"
+"      }\n"
+"      gl_Position = mvp * vertex;\n"
+"      col = color;\n"
+"      tex_c = tex_coord;\n"
+"}\n"
diff --git a/src/modules/engines/gl_common/shader/filter_blur_vert.shd b/src/modules/engines/gl_common/shader/filter_blur_vert.shd
new file mode 100644 (file)
index 0000000..060415d
--- /dev/null
@@ -0,0 +1,29 @@
+#ifdef GL_ES
+precision mediump float;
+#endif
+attribute vec4 vertex;
+attribute vec4 color;
+attribute vec2 tex_coord;
+attribute float r;
+uniform mat4 mvp;
+uniform sampler1D tex_blur;
+varying float weight;
+varying vec4 col;
+varying vec2 tex_c;
+
+void main(){
+       /* FIXME: This index shoudl be tweaked so for 
+               radius 1, I want 3 points at 1/4, 2/4, 3/4 */
+       /*
+       for (float i = 0 ; i <= radius * 2 ; i ++){
+               float pos = i;
+               float r = float(radius);
+               weight += sampler1D(tex_blur, 1.0 / (r * 2.0 * pos));
+       }*/
+       for (float i = 0.0 ; i < r * 2.0 ; i += 1.0){
+               weight += sampler1D(tex_blur, 1.0 / (r * 2.0 * i));
+       }
+       gl_Position = mvp * vertex;
+       col = color;
+       tex_c = tex_coord;
+}
index 0cf3e45..d04370a 100644 (file)
@@ -1557,6 +1557,40 @@ eng_image_native_get(void *data __UNUSED__, void *image)
    return &(n->ns);
 }
 
+static void
+eng_image_draw_filtered(void *data, void *context, void *surface,
+               void *image, Evas_Filter_Info *filter)
+{
+   Render_Engine *re = data;
+
+   if (!image) return;
+   eng_window_use(re->win);
+   evas_gl_common_context_target_surface_set(re->win->gl_context, surface);
+   re->win->gl_context->dc = context;
+
+   evas_gl_common_filter_draw(data, re->win->gl_context, image, filter);
+}
+
+static Filtered_Image *
+eng_image_filtered_get(void *im, uint8_t *key, size_t keylen)
+{
+   return evas_gl_common_image_filtered_get(im, key, keylen);
+}
+
+static Filtered_Image *
+eng_image_filtered_save(void *im, void *fim, uint8_t *key, size_t keylen)
+{
+   return evas_gl_common_image_filtered_save(im, fim, key, keylen);
+}
+
+static void
+eng_image_filtered_free(void *im, Filtered_Image *fim)
+{
+   evas_gl_common_image_filtered_free(im, fim);
+}
+
+
+
 //
 //
 /////////////////////////////////////////////////////////////////////////
@@ -2596,6 +2630,10 @@ module_open(Evas_Module *em)
    ORD(image_mask_create);
    ORD(image_native_set);
    ORD(image_native_get);
+   ORD(image_draw_filtered);
+   ORD(image_filtered_get);
+   ORD(image_filtered_save);
+   ORD(image_filtered_free);
    
    ORD(font_draw);
    
index 2b47815..0c03a2e 100644 (file)
@@ -855,6 +855,88 @@ eng_canvas_alpha_get(void *data __UNUSED__, void *info __UNUSED__)
    return EINA_TRUE;
 }
 
+
+/* Filter API */
+static void
+eng_image_draw_filtered(void *data, void *context, void *surface,
+               void *image, Evas_Filter_Info *filter)
+{
+   Evas_Software_Filter_Fn fn;
+   RGBA_Image *im = image;
+
+   fn = evas_filter_software_get(filter);
+   if (!fn) return;
+   if (im->cache_entry.cache) evas_cache_image_load_data(&im->cache_entry);
+   fn(filter, image, surface);
+
+   return;
+}
+
+static Filtered_Image *
+eng_image_filtered_get(void *image, uint8_t *key, size_t keylen)
+{
+   RGBA_Image *im = image;
+   Filtered_Image *fi;
+   Eina_List *l;
+
+   for (l = im->filtered ; l ; l = l->next)
+     {
+         fi = l->data;
+         if (fi->keylen != keylen) continue;
+         if (memcmp(key, fi->key, keylen) != 0) continue;
+         fi->ref ++;
+         return fi;
+     }
+
+   return NULL;
+}
+
+static Filtered_Image *
+eng_image_filtered_save(void *image, void *fimage, uint8_t *key, size_t keylen)
+{
+   RGBA_Image *im = image;
+   Filtered_Image *fi;
+   Eina_List *l;
+
+   for (l = im->filtered ; l ; l = l->next)
+     {
+        fi = l->data;
+        if (fi->keylen != keylen) continue;
+        if (memcmp(key, fi->key, keylen) == 0) continue;
+        evas_cache_image_drop((void *)fi->image);
+        fi->image = fimage;
+        return fi;
+     }
+
+   fi = calloc(1,sizeof(Filtered_Image));
+   if (!fi) return NULL;
+
+   fi->keylen = keylen;
+   fi->key = malloc(keylen);
+   memcpy(fi->key, key, keylen);
+   fi->image = fimage;
+   fi->ref = 1;
+
+   im->filtered = eina_list_prepend(im->filtered, fi);
+
+   return fi;
+}
+
+static void
+eng_image_filtered_free(void *image, Filtered_Image *fi)
+{
+   RGBA_Image *im = image;
+
+   fi->ref --;
+   if (fi->ref) return;
+
+   free(fi->key);
+   evas_cache_image_drop(&fi->image->cache_entry);
+   fi->image = NULL;
+
+   im->filtered = eina_list_remove(im->filtered, fi);
+}
+
 /*
  *****
  **
@@ -975,6 +1057,10 @@ static Evas_Func func =
      eng_font_pen_coords_get,
      eng_font_text_props_info_create,
      eng_font_right_inset_get,
+     eng_image_draw_filtered,
+     eng_image_filtered_get,
+     eng_image_filtered_save,
+     eng_image_filtered_free,
      NULL, // FIXME: need software mesa for gl rendering <- gl_surface_create
      NULL, // FIXME: need software mesa for gl rendering <- gl_surface_destroy
      NULL, // FIXME: need software mesa for gl rendering <- gl_context_create