diff --git a/legacy/evas/ChangeLog b/legacy/evas/ChangeLog index ebb408c89b..251589995d 100644 --- a/legacy/evas/ChangeLog +++ b/legacy/evas/ChangeLog @@ -255,3 +255,10 @@ 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 ;-) diff --git a/legacy/evas/src/lib/Evas.h b/legacy/evas/src/lib/Evas.h index bf0be2e8b7..29f8914a0f 100644 --- a/legacy/evas/src/lib/Evas.h +++ b/legacy/evas/src/lib/Evas.h @@ -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 diff --git a/legacy/evas/src/lib/canvas/Makefile.am b/legacy/evas/src/lib/canvas/Makefile.am index 3c7d34f6c1..b408ec28b4 100644 --- a/legacy/evas/src/lib/canvas/Makefile.am +++ b/legacy/evas/src/lib/canvas/Makefile.am @@ -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/legacy/evas/src/lib/canvas/evas_filter.c b/legacy/evas/src/lib/canvas/evas_filter.c new file mode 100644 index 0000000000..2f49bec600 --- /dev/null +++ b/legacy/evas/src/lib/canvas/evas_filter.c @@ -0,0 +1,1185 @@ +/* + * Filter implementation for evas + */ + +#include // 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 :*/ diff --git a/legacy/evas/src/lib/engines/common/evas_image_main.c b/legacy/evas/src/lib/engines/common/evas_image_main.c index 9287185368..e4e5d78a9e 100644 --- a/legacy/evas/src/lib/engines/common/evas_image_main.c +++ b/legacy/evas/src/lib/engines/common/evas_image_main.c @@ -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); } diff --git a/legacy/evas/src/lib/include/evas_common.h b/legacy/evas/src/lib/include/evas_common.h index 379b1ff7b8..b3973b83b1 100644 --- a/legacy/evas/src/lib/include/evas_common.h +++ b/legacy/evas/src/lib/include/evas_common.h @@ -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; diff --git a/legacy/evas/src/lib/include/evas_private.h b/legacy/evas/src/lib/include/evas_private.h index b82881dbb8..d9bdd8903e 100644 --- a/legacy/evas/src/lib/include/evas_private.h +++ b/legacy/evas/src/lib/include/evas_private.h @@ -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); diff --git a/legacy/evas/src/modules/engines/gl_common/Makefile.am b/legacy/evas/src/modules/engines/gl_common/Makefile.am index 1f95e92a81..e0a0fbbed6 100644 --- a/legacy/evas/src/modules/engines/gl_common/Makefile.am +++ b/legacy/evas/src/modules/engines/gl_common/Makefile.am @@ -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 + diff --git a/legacy/evas/src/modules/engines/gl_common/evas_gl_common.h b/legacy/evas/src/modules/engines/gl_common/evas_gl_common.h index 0318bcb459..335800561e 100644 --- a/legacy/evas/src/modules/engines/gl_common/evas_gl_common.h +++ b/legacy/evas/src/modules/engines/gl_common/evas_gl_common.h @@ -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); diff --git a/legacy/evas/src/modules/engines/gl_common/evas_gl_context.c b/legacy/evas/src/modules/engines/gl_common/evas_gl_context.c index 4b5eeae635..b38d7d750f 100644 --- a/legacy/evas/src/modules/engines/gl_common/evas_gl_context.c +++ b/legacy/evas/src/modules/engines/gl_common/evas_gl_context.c @@ -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/legacy/evas/src/modules/engines/gl_common/evas_gl_filter.c b/legacy/evas/src/modules/engines/gl_common/evas_gl_filter.c new file mode 100644 index 0000000000..76d8627b4e --- /dev/null +++ b/legacy/evas/src/modules/engines/gl_common/evas_gl_filter.c @@ -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 :*/ diff --git a/legacy/evas/src/modules/engines/gl_common/evas_gl_image.c b/legacy/evas/src/modules/engines/gl_common/evas_gl_image.c index 30297ef740..7f10441953 100644 --- a/legacy/evas/src/modules/engines/gl_common/evas_gl_image.c +++ b/legacy/evas/src/modules/engines/gl_common/evas_gl_image.c @@ -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); diff --git a/legacy/evas/src/modules/engines/gl_common/evas_gl_shader.c b/legacy/evas/src/modules/engines/gl_common/evas_gl_shader.c index 1b89aa3b14..2a5c69e542 100644 --- a/legacy/evas/src/modules/engines/gl_common/evas_gl_shader.c +++ b/legacy/evas/src/modules/engines/gl_common/evas_gl_shader.c @@ -442,6 +442,167 @@ Evas_GL_Program_Source shader_img_bgra_nomul_vert_src = #endif }; +///////////////////////////////////////////// +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/legacy/evas/src/modules/engines/gl_common/shader/filter_blur.h b/legacy/evas/src/modules/engines/gl_common/shader/filter_blur.h new file mode 100644 index 0000000000..69e8c07084 --- /dev/null +++ b/legacy/evas/src/modules/engines/gl_common/shader/filter_blur.h @@ -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/legacy/evas/src/modules/engines/gl_common/shader/filter_blur.shd b/legacy/evas/src/modules/engines/gl_common/shader/filter_blur.shd new file mode 100644 index 0000000000..59b580919c --- /dev/null +++ b/legacy/evas/src/modules/engines/gl_common/shader/filter_blur.shd @@ -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/legacy/evas/src/modules/engines/gl_common/shader/filter_blur_bgra.h b/legacy/evas/src/modules/engines/gl_common/shader/filter_blur_bgra.h new file mode 100644 index 0000000000..4dc5f37c90 --- /dev/null +++ b/legacy/evas/src/modules/engines/gl_common/shader/filter_blur_bgra.h @@ -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/legacy/evas/src/modules/engines/gl_common/shader/filter_blur_bgra.shd b/legacy/evas/src/modules/engines/gl_common/shader/filter_blur_bgra.shd new file mode 100644 index 0000000000..efd7932df3 --- /dev/null +++ b/legacy/evas/src/modules/engines/gl_common/shader/filter_blur_bgra.shd @@ -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/legacy/evas/src/modules/engines/gl_common/shader/filter_blur_bgra_nomul.h b/legacy/evas/src/modules/engines/gl_common/shader/filter_blur_bgra_nomul.h new file mode 100644 index 0000000000..4dc5f37c90 --- /dev/null +++ b/legacy/evas/src/modules/engines/gl_common/shader/filter_blur_bgra_nomul.h @@ -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/legacy/evas/src/modules/engines/gl_common/shader/filter_blur_bgra_nomul.shd b/legacy/evas/src/modules/engines/gl_common/shader/filter_blur_bgra_nomul.shd new file mode 100644 index 0000000000..efd7932df3 --- /dev/null +++ b/legacy/evas/src/modules/engines/gl_common/shader/filter_blur_bgra_nomul.shd @@ -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/legacy/evas/src/modules/engines/gl_common/shader/filter_blur_nomul.h b/legacy/evas/src/modules/engines/gl_common/shader/filter_blur_nomul.h new file mode 100644 index 0000000000..4dc5f37c90 --- /dev/null +++ b/legacy/evas/src/modules/engines/gl_common/shader/filter_blur_nomul.h @@ -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/legacy/evas/src/modules/engines/gl_common/shader/filter_blur_nomul.shd b/legacy/evas/src/modules/engines/gl_common/shader/filter_blur_nomul.shd new file mode 100644 index 0000000000..efd7932df3 --- /dev/null +++ b/legacy/evas/src/modules/engines/gl_common/shader/filter_blur_nomul.shd @@ -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/legacy/evas/src/modules/engines/gl_common/shader/filter_blur_vert.h b/legacy/evas/src/modules/engines/gl_common/shader/filter_blur_vert.h new file mode 100644 index 0000000000..80fd7337d5 --- /dev/null +++ b/legacy/evas/src/modules/engines/gl_common/shader/filter_blur_vert.h @@ -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/legacy/evas/src/modules/engines/gl_common/shader/filter_blur_vert.shd b/legacy/evas/src/modules/engines/gl_common/shader/filter_blur_vert.shd new file mode 100644 index 0000000000..060415de2a --- /dev/null +++ b/legacy/evas/src/modules/engines/gl_common/shader/filter_blur_vert.shd @@ -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; +} diff --git a/legacy/evas/src/modules/engines/gl_x11/evas_engine.c b/legacy/evas/src/modules/engines/gl_x11/evas_engine.c index 0cf3e45668..d04370a70f 100644 --- a/legacy/evas/src/modules/engines/gl_x11/evas_engine.c +++ b/legacy/evas/src/modules/engines/gl_x11/evas_engine.c @@ -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); diff --git a/legacy/evas/src/modules/engines/software_generic/evas_engine.c b/legacy/evas/src/modules/engines/software_generic/evas_engine.c index 2b47815505..0c03a2e5dd 100644 --- a/legacy/evas/src/modules/engines/software_generic/evas_engine.c +++ b/legacy/evas/src/modules/engines/software_generic/evas_engine.c @@ -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