2014-02-12 00:52:01 -08:00
|
|
|
/*
|
|
|
|
* \@file evas_filter.c
|
|
|
|
*
|
|
|
|
* Infrastructure for simple filters applied to RGBA and Alpha buffers.
|
2013-12-08 22:57:50 -08:00
|
|
|
* Originally used by font effects.
|
|
|
|
*
|
|
|
|
* Filters include:
|
|
|
|
* - Blur (Gaussian, Box, Motion) and Shadows
|
|
|
|
* - Bump maps (light effects)
|
|
|
|
* - Displacement maps
|
|
|
|
* - Color curves
|
|
|
|
* - Blending and masking
|
2014-02-12 00:52:01 -08:00
|
|
|
*
|
|
|
|
* The reference documentation can be found in evas_filter_parser.c
|
2013-12-08 22:57:50 -08:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "evas_filter.h"
|
|
|
|
#include "evas_private.h"
|
|
|
|
#include "evas_filter_private.h"
|
|
|
|
|
2014-01-16 18:19:02 -08:00
|
|
|
#ifdef EVAS_CSERVE2
|
|
|
|
# include "evas_cs2_private.h"
|
|
|
|
#endif
|
|
|
|
|
2013-12-08 22:57:50 -08:00
|
|
|
static void _buffer_free(Evas_Filter_Buffer *fb);
|
|
|
|
static void _command_del(Evas_Filter_Context *ctx, Evas_Filter_Command *cmd);
|
2014-03-06 16:36:16 -08:00
|
|
|
static RGBA_Image *_rgba_image_alloc(Evas_Filter_Buffer const *fb, void *data);
|
2013-12-08 22:57:50 -08:00
|
|
|
|
2013-12-12 00:46:46 -08:00
|
|
|
#ifdef CLAMP
|
|
|
|
# undef CLAMP
|
|
|
|
#endif
|
|
|
|
#define CLAMP(a,b,c) MIN(MAX((b),(a)),(c))
|
|
|
|
|
2013-12-08 22:57:50 -08:00
|
|
|
#define DRAW_COLOR_SET(r, g, b, a) do { cmd->draw.R = r; cmd->draw.G = g; cmd->draw.B = b; cmd->draw.A = a; } while (0)
|
2014-01-02 01:44:01 -08:00
|
|
|
#define DRAW_CLIP_SET(_x, _y, _w, _h) do { cmd->draw.clip.x = _x; cmd->draw.clip.y = _y; cmd->draw.clip.w = _w; cmd->draw.clip.h = _h; } while (0)
|
2013-12-31 00:51:09 -08:00
|
|
|
#define DRAW_FILL_SET(fmode) do { cmd->draw.fillmode = fmode; } while (0)
|
2013-12-08 22:57:50 -08:00
|
|
|
|
|
|
|
typedef struct _Evas_Filter_Thread_Command Evas_Filter_Thread_Command;
|
|
|
|
struct _Evas_Filter_Thread_Command
|
|
|
|
{
|
|
|
|
Evas_Filter_Context *ctx;
|
|
|
|
RGBA_Image *src, *mask, *dst;
|
|
|
|
Evas_Filter_Apply_Func func;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/* Main functions */
|
|
|
|
|
|
|
|
Evas_Filter_Context *
|
2014-01-22 23:54:50 -08:00
|
|
|
evas_filter_context_new(Evas_Public_Data *evas, Eina_Bool async)
|
2013-12-08 22:57:50 -08:00
|
|
|
{
|
|
|
|
Evas_Filter_Context *ctx;
|
|
|
|
|
2014-01-16 18:19:02 -08:00
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(evas, NULL);
|
|
|
|
|
2013-12-08 22:57:50 -08:00
|
|
|
ctx = calloc(1, sizeof(Evas_Filter_Context));
|
|
|
|
if (!ctx) return NULL;
|
|
|
|
|
|
|
|
ctx->evas = evas;
|
2014-01-22 23:54:50 -08:00
|
|
|
ctx->async = async;
|
2014-03-06 17:32:47 -08:00
|
|
|
|
|
|
|
/* Note:
|
|
|
|
* For now, we need to detect whether the engine is full SW or GL.
|
|
|
|
* In case of GL, we will have two buffers in parallel:
|
|
|
|
* RGBA_Image backing and a GL texture (glimage). We can't just leave it
|
|
|
|
* to the engine to handle the image data since it will try to discard the
|
|
|
|
* original buffer as early as possible to save memory, but we still need
|
|
|
|
* it for filtering.
|
|
|
|
* In the future, Evas_Engine functions need to be added to abstract this
|
|
|
|
* better and implement filters direcly with shaders.
|
|
|
|
*/
|
|
|
|
ctx->gl_engine = (evas->engine.func->gl_surface_read_pixels != NULL);
|
|
|
|
if (ctx->gl_engine)
|
|
|
|
DBG("Detected GL engine. All filters will still run in software (SLOW).");
|
2014-01-16 18:19:02 -08:00
|
|
|
|
2013-12-08 22:57:50 -08:00
|
|
|
return ctx;
|
|
|
|
}
|
|
|
|
|
2014-02-13 19:07:54 -08:00
|
|
|
/* Private function to reset the filter context. Used from parser.c */
|
2013-12-08 22:57:50 -08:00
|
|
|
void
|
|
|
|
evas_filter_context_clear(Evas_Filter_Context *ctx)
|
|
|
|
{
|
|
|
|
Evas_Filter_Buffer *fb;
|
|
|
|
Evas_Filter_Command *cmd;
|
|
|
|
|
|
|
|
if (!ctx) return;
|
|
|
|
|
|
|
|
EINA_LIST_FREE(ctx->buffers, fb)
|
|
|
|
_buffer_free(fb);
|
|
|
|
EINA_INLIST_FREE(ctx->commands, cmd)
|
|
|
|
_command_del(ctx, cmd);
|
|
|
|
|
|
|
|
ctx->buffers = NULL;
|
|
|
|
ctx->commands = NULL;
|
|
|
|
ctx->last_buffer_id = 0;
|
|
|
|
ctx->last_command_id = 0;
|
|
|
|
|
|
|
|
// Note: don't reset post_run, as it it set by the client
|
|
|
|
}
|
|
|
|
|
2014-01-22 21:58:05 -08:00
|
|
|
static void
|
2014-03-06 16:36:16 -08:00
|
|
|
_backing_free(Evas_Filter_Context *ctx, RGBA_Image *im)
|
2014-01-22 21:58:05 -08:00
|
|
|
{
|
2014-03-06 16:36:16 -08:00
|
|
|
if (!im) return;
|
2014-01-22 21:58:05 -08:00
|
|
|
|
|
|
|
if (!ctx->gl_engine)
|
2014-01-22 23:54:50 -08:00
|
|
|
{
|
|
|
|
if (!ctx->async)
|
2014-03-06 16:36:16 -08:00
|
|
|
ENFN->image_free(ENDT, im);
|
2014-01-22 23:54:50 -08:00
|
|
|
}
|
2014-01-22 21:58:05 -08:00
|
|
|
else
|
|
|
|
{
|
2014-02-09 18:05:07 -08:00
|
|
|
#ifdef EVAS_CSERVE2
|
|
|
|
if (evas_cserve2_use_get())
|
2014-03-06 16:36:16 -08:00
|
|
|
evas_cache2_image_close(&im->cache_entry);
|
2014-02-09 18:05:07 -08:00
|
|
|
else
|
|
|
|
#endif
|
2014-03-06 16:36:16 -08:00
|
|
|
evas_cache_image_drop(&im->cache_entry);
|
2014-01-22 21:58:05 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-01-16 18:19:02 -08:00
|
|
|
static void
|
|
|
|
_filter_buffer_backing_free(Evas_Filter_Buffer *fb)
|
|
|
|
{
|
|
|
|
if (!fb) return;
|
|
|
|
|
2014-03-06 16:36:16 -08:00
|
|
|
if (!fb->stolen)
|
2014-01-22 21:58:05 -08:00
|
|
|
{
|
2014-03-06 16:36:16 -08:00
|
|
|
if (fb->allocated)
|
|
|
|
_backing_free(fb->ctx, fb->backing);
|
|
|
|
if (fb->glimage && fb->allocated_gl)
|
|
|
|
fb->ENFN->image_free(fb->ENDT, fb->glimage);
|
|
|
|
fb->backing = NULL;
|
|
|
|
fb->glimage = NULL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (!fb->ctx->gl_engine)
|
2014-03-02 23:22:40 -08:00
|
|
|
{
|
2014-03-06 16:36:16 -08:00
|
|
|
fb->delete_me = fb->allocated;
|
2014-03-02 23:22:40 -08:00
|
|
|
}
|
2014-03-06 16:36:16 -08:00
|
|
|
else if (fb->glimage && fb->allocated)
|
|
|
|
{
|
|
|
|
_backing_free(fb->ctx, fb->backing);
|
|
|
|
fb->backing = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* GL engine stuff: read-back from texture */
|
|
|
|
static Eina_Bool
|
|
|
|
_filter_buffer_glimage_pixels_read(Evas_Filter_Buffer *fb)
|
|
|
|
{
|
|
|
|
Eina_Bool ok;
|
|
|
|
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(fb, EINA_FALSE);
|
|
|
|
EINA_SAFETY_ON_FALSE_RETURN_VAL(fb->ctx->gl_engine, EINA_FALSE);
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(fb->glimage, EINA_FALSE);
|
|
|
|
|
|
|
|
if (fb->backing)
|
|
|
|
return EINA_TRUE;
|
|
|
|
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(fb->ENFN->gl_surface_lock, EINA_FALSE);
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(fb->ENFN->gl_surface_read_pixels, EINA_FALSE);
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(fb->ENFN->gl_surface_unlock, EINA_FALSE);
|
|
|
|
|
|
|
|
fb->backing = _rgba_image_alloc(fb, NULL);
|
|
|
|
fb->allocated = EINA_TRUE;
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(fb->backing, EINA_FALSE);
|
|
|
|
|
|
|
|
ok = fb->ENFN->gl_surface_lock(fb->ENDT, fb->glimage);
|
|
|
|
if (!ok)
|
|
|
|
{
|
|
|
|
ERR("Failed to lock the image pixels");
|
|
|
|
return EINA_FALSE;
|
2014-01-22 21:58:05 -08:00
|
|
|
}
|
|
|
|
|
2014-03-06 16:36:16 -08:00
|
|
|
ok = fb->ENFN->gl_surface_read_pixels(fb->ENDT, fb->glimage,
|
|
|
|
0, 0, fb->w, fb->h, fb->alpha_only
|
|
|
|
? EVAS_COLORSPACE_GRY8
|
|
|
|
: EVAS_COLORSPACE_ARGB8888,
|
|
|
|
fb->backing->image.data);
|
|
|
|
if (!ok)
|
|
|
|
ERR("Could not read the image pixels!");
|
2014-01-16 18:19:02 -08:00
|
|
|
|
2014-03-06 16:36:16 -08:00
|
|
|
ok &= fb->ENFN->gl_surface_unlock(fb->ENDT, fb->glimage);
|
|
|
|
return ok;
|
2014-01-16 18:19:02 -08:00
|
|
|
}
|
|
|
|
|
2013-12-08 22:57:50 -08:00
|
|
|
/** @hidden private render proxy objects */
|
|
|
|
void
|
|
|
|
evas_filter_context_proxy_render_all(Evas_Filter_Context *ctx, Eo *eo_obj,
|
|
|
|
Eina_Bool do_async)
|
|
|
|
{
|
|
|
|
Evas_Object_Protected_Data *source;
|
|
|
|
Evas_Object_Protected_Data *obj;
|
|
|
|
Evas_Filter_Buffer *fb;
|
|
|
|
Eina_List *li;
|
|
|
|
|
2014-06-02 06:47:59 -07:00
|
|
|
obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
|
2013-12-08 22:57:50 -08:00
|
|
|
|
2014-03-01 21:55:42 -08:00
|
|
|
if (!ctx->has_proxies) return;
|
2013-12-08 22:57:50 -08:00
|
|
|
EINA_LIST_FOREACH(ctx->buffers, li, fb)
|
|
|
|
if (fb->source)
|
|
|
|
{
|
|
|
|
// TODO: Lock current object as proxyrendering (see image obj)
|
2014-06-02 06:47:59 -07:00
|
|
|
source = eo_data_scope_get(fb->source, EVAS_OBJECT_CLASS);
|
2013-12-08 22:57:50 -08:00
|
|
|
if (source->proxy->surface && !source->proxy->redraw)
|
|
|
|
{
|
2014-03-10 00:05:55 -07:00
|
|
|
DBG("Source already rendered: '%s' of type '%s'",
|
|
|
|
fb->source_name, eo_class_name_get(eo_class_get(fb->source)));
|
2014-01-16 18:19:02 -08:00
|
|
|
_filter_buffer_backing_free(fb);
|
2013-12-08 22:57:50 -08:00
|
|
|
fb->w = source->cur->geometry.w;
|
|
|
|
fb->h = source->cur->geometry.h;
|
2014-03-06 16:36:16 -08:00
|
|
|
if (!ctx->gl_engine)
|
|
|
|
{
|
|
|
|
fb->backing = source->proxy->surface;
|
|
|
|
fb->allocated = EINA_FALSE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
fb->glimage = source->proxy->surface;
|
|
|
|
fb->allocated_gl = EINA_FALSE;
|
|
|
|
_filter_buffer_glimage_pixels_read(fb);
|
|
|
|
}
|
2013-12-08 22:57:50 -08:00
|
|
|
fb->alpha_only = EINA_FALSE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-03-10 00:05:55 -07:00
|
|
|
DBG("Source needs to be rendered: '%s' of type '%s' (%s)",
|
|
|
|
fb->source_name, eo_class_name_get(eo_class_get(fb->source)),
|
|
|
|
source->proxy->redraw ? "redraw" : "no surface");
|
2014-10-22 23:27:40 -07:00
|
|
|
evas_render_proxy_subrender(ctx->evas->evas, fb->source, eo_obj, obj, do_async);
|
2014-01-16 18:19:02 -08:00
|
|
|
_filter_buffer_backing_free(fb);
|
2013-12-08 22:57:50 -08:00
|
|
|
fb->w = source->cur->geometry.w;
|
|
|
|
fb->h = source->cur->geometry.h;
|
2014-03-06 16:36:16 -08:00
|
|
|
if (!ctx->gl_engine)
|
|
|
|
{
|
|
|
|
fb->backing = source->proxy->surface;
|
|
|
|
fb->allocated = EINA_FALSE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
fb->glimage = source->proxy->surface;
|
|
|
|
fb->allocated_gl = EINA_FALSE;
|
|
|
|
_filter_buffer_glimage_pixels_read(fb);
|
|
|
|
}
|
2013-12-08 22:57:50 -08:00
|
|
|
fb->alpha_only = EINA_FALSE;
|
|
|
|
}
|
2014-01-22 23:54:50 -08:00
|
|
|
DBG("Source has dimensions %dx%d (buffer %d)", fb->w, fb->h, fb->id);
|
2013-12-08 22:57:50 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
evas_filter_context_destroy(Evas_Filter_Context *ctx)
|
|
|
|
{
|
|
|
|
Evas_Filter_Buffer *fb;
|
|
|
|
Evas_Filter_Command *cmd;
|
|
|
|
|
|
|
|
if (!ctx) return;
|
|
|
|
|
|
|
|
EINA_LIST_FREE(ctx->buffers, fb)
|
|
|
|
_buffer_free(fb);
|
|
|
|
EINA_INLIST_FREE(ctx->commands, cmd)
|
|
|
|
_command_del(ctx, cmd);
|
|
|
|
|
|
|
|
free(ctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
evas_filter_context_post_run_callback_set(Evas_Filter_Context *ctx,
|
|
|
|
Evas_Filter_Cb cb, void *data)
|
|
|
|
{
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN(ctx);
|
|
|
|
ctx->post_run.cb = cb;
|
|
|
|
ctx->post_run.data = data;
|
|
|
|
}
|
|
|
|
|
|
|
|
static Evas_Filter_Buffer *
|
|
|
|
_buffer_new(Evas_Filter_Context *ctx, int w, int h, Eina_Bool alpha_only)
|
|
|
|
{
|
|
|
|
Evas_Filter_Buffer *fb;
|
|
|
|
|
|
|
|
fb = calloc(1, sizeof(Evas_Filter_Buffer));
|
|
|
|
if (!fb) return NULL;
|
|
|
|
|
|
|
|
fb->id = ++(ctx->last_buffer_id);
|
|
|
|
fb->ctx = ctx;
|
|
|
|
fb->alpha_only = alpha_only;
|
|
|
|
fb->transient = EINA_TRUE;
|
|
|
|
fb->w = w;
|
|
|
|
fb->h = h;
|
|
|
|
|
|
|
|
ctx->buffers = eina_list_append(ctx->buffers, fb);
|
|
|
|
return fb;
|
|
|
|
}
|
|
|
|
|
2013-12-11 22:54:33 -08:00
|
|
|
static RGBA_Image *
|
2014-01-02 18:11:40 -08:00
|
|
|
_rgba_image_alloc(Evas_Filter_Buffer const *fb, void *data)
|
2013-12-08 22:57:50 -08:00
|
|
|
{
|
|
|
|
Evas_Colorspace cspace;
|
2013-12-11 22:54:33 -08:00
|
|
|
RGBA_Image *image;
|
|
|
|
size_t sz;
|
|
|
|
|
|
|
|
cspace = fb->alpha_only ? EVAS_COLORSPACE_GRY8 : EVAS_COLORSPACE_ARGB8888;
|
2014-01-16 18:19:02 -08:00
|
|
|
if (!fb->ctx->gl_engine)
|
2014-01-02 18:11:40 -08:00
|
|
|
{
|
2014-01-16 18:19:02 -08:00
|
|
|
if (!data)
|
|
|
|
{
|
|
|
|
image = fb->ENFN->image_new_from_copied_data
|
|
|
|
(fb->ENDT, fb->w, fb->h, NULL, EINA_TRUE, cspace);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
image = fb->ENFN->image_new_from_data
|
|
|
|
(fb->ENDT, fb->w, fb->h, data, EINA_TRUE, cspace);
|
|
|
|
}
|
2014-01-02 18:11:40 -08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-01-16 18:19:02 -08:00
|
|
|
// FIXME: Directly calling the alloc functions since we want to use sw surfaces.
|
|
|
|
|
|
|
|
if (!data)
|
|
|
|
{
|
2014-02-09 18:05:07 -08:00
|
|
|
#ifdef EVAS_CSERVE2
|
|
|
|
if (evas_cserve2_use_get())
|
|
|
|
image = (RGBA_Image *) evas_cache2_image_copied_data
|
|
|
|
(evas_common_image_cache2_get(), fb->w, fb->h, NULL, EINA_TRUE, cspace);
|
|
|
|
else
|
|
|
|
#endif
|
2014-01-16 18:19:02 -08:00
|
|
|
image = (RGBA_Image *) evas_cache_image_copied_data
|
|
|
|
(evas_common_image_cache_get(), fb->w, fb->h, NULL, EINA_TRUE, cspace);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-02-09 18:05:07 -08:00
|
|
|
#ifdef EVAS_CSERVE2
|
|
|
|
if (evas_cserve2_use_get())
|
2014-01-16 18:19:02 -08:00
|
|
|
image = (RGBA_Image *) evas_cache2_image_data
|
|
|
|
(evas_common_image_cache2_get(), fb->w, fb->h, data, EINA_TRUE, cspace);
|
2014-02-09 18:05:07 -08:00
|
|
|
else
|
|
|
|
#endif
|
|
|
|
image = (RGBA_Image *) evas_cache_image_data
|
|
|
|
(evas_common_image_cache_get(), fb->w, fb->h, data, EINA_TRUE, cspace);
|
2014-01-16 18:19:02 -08:00
|
|
|
}
|
2014-01-02 18:11:40 -08:00
|
|
|
}
|
2014-05-07 08:32:49 -07:00
|
|
|
if (!image) return NULL;
|
2013-12-08 22:57:50 -08:00
|
|
|
|
2013-12-11 22:54:33 -08:00
|
|
|
if (fb->alpha_only)
|
|
|
|
sz = image->cache_entry.w * image->cache_entry.h * sizeof(DATA8);
|
|
|
|
else
|
|
|
|
sz = image->cache_entry.w * image->cache_entry.h * sizeof(DATA32);
|
2014-01-02 18:11:40 -08:00
|
|
|
if (!data) memset(image->image.data, 0, sz);
|
2013-12-11 22:54:33 -08:00
|
|
|
|
|
|
|
return image;
|
|
|
|
}
|
|
|
|
|
2014-01-22 21:58:05 -08:00
|
|
|
Eina_Bool
|
2014-01-22 23:54:50 -08:00
|
|
|
evas_filter_context_buffers_allocate_all(Evas_Filter_Context *ctx,
|
|
|
|
unsigned w, unsigned h)
|
2014-01-22 21:58:05 -08:00
|
|
|
{
|
2014-01-22 23:54:50 -08:00
|
|
|
Evas_Filter_Command *cmd;
|
2014-01-22 21:58:05 -08:00
|
|
|
Evas_Filter_Buffer *fb;
|
|
|
|
Eina_List *li;
|
|
|
|
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, EINA_FALSE);
|
2014-01-22 23:54:50 -08:00
|
|
|
ctx->w = w;
|
|
|
|
ctx->h = h;
|
|
|
|
|
|
|
|
//DBG("Allocating all buffers based on output size %ux%u", w, h);
|
|
|
|
|
|
|
|
EINA_INLIST_FOREACH(ctx->commands, cmd)
|
2014-01-22 21:58:05 -08:00
|
|
|
{
|
2014-01-22 23:54:50 -08:00
|
|
|
Evas_Filter_Fill_Mode fillmode = cmd->draw.fillmode;
|
2014-02-11 17:14:38 -08:00
|
|
|
Evas_Filter_Buffer *in, *out;
|
2014-01-22 23:54:50 -08:00
|
|
|
|
|
|
|
in = cmd->input;
|
|
|
|
if (!in->w && !in->h)
|
|
|
|
{
|
|
|
|
in->w = w;
|
|
|
|
in->h = h;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fillmode & EVAS_FILTER_FILL_MODE_STRETCH_XY)
|
|
|
|
{
|
|
|
|
unsigned sw = w, sh = h;
|
|
|
|
|
|
|
|
switch (cmd->mode)
|
|
|
|
{
|
|
|
|
case EVAS_FILTER_MODE_BLEND:
|
|
|
|
in = cmd->input;
|
|
|
|
break;
|
|
|
|
case EVAS_FILTER_MODE_BUMP:
|
|
|
|
case EVAS_FILTER_MODE_DISPLACE:
|
|
|
|
case EVAS_FILTER_MODE_MASK:
|
|
|
|
in = cmd->mask;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
CRI("Invalid fillmode set for command %d", cmd->mode);
|
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
2014-01-22 21:58:05 -08:00
|
|
|
|
2014-01-22 23:54:50 -08:00
|
|
|
if (in->w) sw = in->w;
|
|
|
|
if (in->h) sh = in->h;
|
|
|
|
|
|
|
|
if ((sw != w) || (sh != h))
|
|
|
|
{
|
|
|
|
if (fillmode & EVAS_FILTER_FILL_MODE_STRETCH_X)
|
|
|
|
sw = w;
|
|
|
|
if (fillmode & EVAS_FILTER_FILL_MODE_STRETCH_Y)
|
|
|
|
sh = h;
|
|
|
|
|
|
|
|
//DBG("Allocating temporary buffer of size %ux%u", sw, sh);
|
|
|
|
fb = evas_filter_buffer_alloc_new(ctx, sw, sh, in->alpha_only);
|
2014-03-11 00:18:41 -07:00
|
|
|
if (!fb) goto alloc_fail;
|
2014-01-22 23:54:50 -08:00
|
|
|
fb->transient = EINA_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cmd->draw.need_temp_buffer)
|
|
|
|
{
|
|
|
|
unsigned sw = w, sh = h;
|
|
|
|
|
|
|
|
in = cmd->input;
|
|
|
|
if (in->w) sw = in->w;
|
|
|
|
if (in->h) sh = in->h;
|
|
|
|
|
|
|
|
//DBG("Allocating temporary buffer of size %ux%u", sw, sh);
|
|
|
|
fb = evas_filter_buffer_alloc_new(ctx, sw, sh, in->alpha_only);
|
2014-03-11 00:18:41 -07:00
|
|
|
if (!fb) goto alloc_fail;
|
2014-01-22 23:54:50 -08:00
|
|
|
fb->transient = EINA_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
out = cmd->output;
|
|
|
|
if (!out->w && !out->h)
|
|
|
|
{
|
|
|
|
out->w = w;
|
|
|
|
out->h = h;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
EINA_LIST_FOREACH(ctx->buffers, li, fb)
|
|
|
|
{
|
2014-03-06 16:36:16 -08:00
|
|
|
RGBA_Image *im;
|
|
|
|
im = fb->backing;
|
|
|
|
if (im)
|
2014-01-22 21:58:05 -08:00
|
|
|
{
|
2014-02-06 23:06:46 -08:00
|
|
|
if (ctx->async)
|
|
|
|
{
|
2014-03-06 16:36:16 -08:00
|
|
|
im->cache_entry.references++;
|
|
|
|
evas_unref_queue_image_put(ctx->evas, &im->cache_entry);
|
2014-02-06 23:06:46 -08:00
|
|
|
}
|
2014-01-22 21:58:05 -08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2014-01-22 23:54:50 -08:00
|
|
|
if (fb->source)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (fb->glimage)
|
|
|
|
continue;
|
|
|
|
|
2014-01-22 21:58:05 -08:00
|
|
|
if (!fb->w && !fb->h)
|
|
|
|
{
|
2014-03-06 16:36:16 -08:00
|
|
|
ERR("Size of buffer %d should be known at this point. Is this a dangling buffer?", fb->id);
|
2014-01-22 23:54:50 -08:00
|
|
|
continue;
|
2014-01-22 21:58:05 -08:00
|
|
|
}
|
2014-01-22 23:54:50 -08:00
|
|
|
|
2014-02-06 18:22:36 -08:00
|
|
|
//DBG("Allocating buffer of size %ux%u alpha %d", fb->w, fb->h, fb->alpha_only);
|
2014-03-06 16:36:16 -08:00
|
|
|
im = _rgba_image_alloc(fb, NULL);
|
2014-03-11 00:18:41 -07:00
|
|
|
if (!im) goto alloc_fail;
|
2014-01-22 21:58:05 -08:00
|
|
|
|
2014-03-06 16:36:16 -08:00
|
|
|
fb->backing = im;
|
|
|
|
fb->allocated = (im != NULL);
|
2014-01-23 17:54:51 -08:00
|
|
|
if (ctx->async && fb->allocated)
|
2014-03-06 16:36:16 -08:00
|
|
|
evas_unref_queue_image_put(ctx->evas, &im->cache_entry);
|
2014-01-22 21:58:05 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
return EINA_TRUE;
|
2014-03-11 00:18:41 -07:00
|
|
|
|
|
|
|
alloc_fail:
|
|
|
|
ERR("Buffer allocation failed! Context size: %dx%d", w, h);
|
|
|
|
return EINA_FALSE;
|
2014-01-22 21:58:05 -08:00
|
|
|
}
|
2013-12-08 22:57:50 -08:00
|
|
|
|
|
|
|
int
|
|
|
|
evas_filter_buffer_empty_new(Evas_Filter_Context *ctx, Eina_Bool alpha_only)
|
|
|
|
{
|
|
|
|
Evas_Filter_Buffer *fb;
|
|
|
|
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, -1);
|
|
|
|
|
|
|
|
fb = _buffer_new(ctx, 0, 0, alpha_only);
|
|
|
|
if (!fb) return -1;
|
|
|
|
|
|
|
|
fb->transient = EINA_FALSE;
|
|
|
|
|
|
|
|
return fb->id;
|
|
|
|
}
|
|
|
|
|
|
|
|
Eina_Bool
|
2014-01-22 23:54:50 -08:00
|
|
|
_filter_buffer_data_set(Evas_Filter_Context *ctx, int bufid, void *data,
|
|
|
|
int w, int h, Eina_Bool alpha_only)
|
2013-12-08 22:57:50 -08:00
|
|
|
{
|
|
|
|
Evas_Filter_Buffer *fb;
|
|
|
|
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, EINA_FALSE);
|
|
|
|
|
|
|
|
fb = _filter_buffer_get(ctx, bufid);
|
|
|
|
if (!fb) return EINA_FALSE;
|
|
|
|
|
2014-01-16 18:19:02 -08:00
|
|
|
_filter_buffer_backing_free(fb);
|
2014-01-02 18:11:40 -08:00
|
|
|
if (w <= 0 || h <= 0)
|
|
|
|
return EINA_FALSE;
|
2013-12-08 22:57:50 -08:00
|
|
|
|
|
|
|
EINA_SAFETY_ON_FALSE_RETURN_VAL(fb->backing == NULL, EINA_FALSE);
|
|
|
|
// TODO: Check input parameters?
|
|
|
|
fb->alpha_only = alpha_only;
|
|
|
|
fb->w = w;
|
|
|
|
fb->h = h;
|
|
|
|
|
2014-01-02 18:11:40 -08:00
|
|
|
fb->backing = _rgba_image_alloc(fb, data);
|
|
|
|
fb->allocated = (!data && (fb->backing != NULL));
|
2014-01-23 17:54:51 -08:00
|
|
|
if (ctx->async && fb->allocated)
|
|
|
|
evas_unref_queue_image_put(ctx->evas, fb->backing);
|
2013-12-11 22:54:33 -08:00
|
|
|
return fb->allocated;
|
2013-12-08 22:57:50 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2014-03-06 16:36:16 -08:00
|
|
|
evas_filter_buffer_image_new(Evas_Filter_Context *ctx, void *image)
|
2013-12-08 22:57:50 -08:00
|
|
|
{
|
|
|
|
Evas_Filter_Buffer *fb;
|
|
|
|
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, -1);
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(image, -1);
|
|
|
|
|
|
|
|
fb = calloc(1, sizeof(Evas_Filter_Buffer));
|
|
|
|
if (!fb) return -1;
|
|
|
|
|
|
|
|
fb->id = ++(ctx->last_buffer_id);
|
|
|
|
fb->ctx = ctx;
|
2014-03-06 16:36:16 -08:00
|
|
|
if (!fb->ctx->gl_engine)
|
|
|
|
{
|
|
|
|
fb->backing = image;
|
|
|
|
fb->allocated = EINA_FALSE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
fb->glimage = image;
|
|
|
|
fb->allocated_gl = EINA_FALSE;
|
|
|
|
}
|
|
|
|
ENFN->image_size_get(ENDT, image, &fb->w, &fb->h);
|
|
|
|
fb->alpha_only = (ENFN->image_colorspace_get(ENDT, image)
|
|
|
|
== EVAS_COLORSPACE_GRY8);
|
2013-12-08 22:57:50 -08:00
|
|
|
|
|
|
|
ctx->buffers = eina_list_append(ctx->buffers, fb);
|
|
|
|
return fb->id;
|
|
|
|
}
|
|
|
|
|
2014-01-22 23:54:50 -08:00
|
|
|
Evas_Filter_Buffer *
|
|
|
|
_filter_buffer_data_new(Evas_Filter_Context *ctx, void *data, int w, int h,
|
|
|
|
Eina_Bool alpha_only)
|
2013-12-08 22:57:50 -08:00
|
|
|
{
|
|
|
|
Evas_Filter_Buffer *fb;
|
|
|
|
|
2014-01-22 23:54:50 -08:00
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, NULL);
|
|
|
|
EINA_SAFETY_ON_FALSE_RETURN_VAL(w > 0 && h > 0, NULL);
|
2013-12-08 22:57:50 -08:00
|
|
|
|
|
|
|
fb = calloc(1, sizeof(Evas_Filter_Buffer));
|
2014-01-22 23:54:50 -08:00
|
|
|
if (!fb) return NULL;
|
2013-12-08 22:57:50 -08:00
|
|
|
|
|
|
|
fb->id = ++(ctx->last_buffer_id);
|
|
|
|
fb->ctx = ctx;
|
|
|
|
ctx->buffers = eina_list_append(ctx->buffers, fb);
|
|
|
|
|
2014-01-22 23:54:50 -08:00
|
|
|
if (!_filter_buffer_data_set(ctx, fb->id, data, w, h, alpha_only))
|
2013-12-08 22:57:50 -08:00
|
|
|
{
|
|
|
|
ctx->buffers = eina_list_remove(ctx->buffers, fb);
|
|
|
|
free(fb);
|
2014-01-22 23:54:50 -08:00
|
|
|
return NULL;
|
2013-12-08 22:57:50 -08:00
|
|
|
}
|
|
|
|
|
2014-01-22 23:54:50 -08:00
|
|
|
return fb;
|
2013-12-08 22:57:50 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
_buffer_free(Evas_Filter_Buffer *fb)
|
|
|
|
{
|
2014-01-16 18:19:02 -08:00
|
|
|
_filter_buffer_backing_free(fb);
|
2013-12-08 22:57:50 -08:00
|
|
|
free(fb);
|
|
|
|
}
|
|
|
|
|
|
|
|
Evas_Filter_Buffer *
|
|
|
|
_filter_buffer_get(Evas_Filter_Context *ctx, int bufid)
|
|
|
|
{
|
|
|
|
Evas_Filter_Buffer *buffer;
|
|
|
|
Eina_List *l;
|
|
|
|
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, NULL);
|
|
|
|
|
|
|
|
EINA_LIST_FOREACH(ctx->buffers, l, buffer)
|
|
|
|
if (buffer->id == bufid) return buffer;
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void *
|
|
|
|
evas_filter_buffer_backing_get(Evas_Filter_Context *ctx, int bufid)
|
|
|
|
{
|
|
|
|
Evas_Filter_Buffer *buffer;
|
|
|
|
|
|
|
|
buffer = _filter_buffer_get(ctx, bufid);
|
|
|
|
if (!buffer) return NULL;
|
|
|
|
|
|
|
|
return buffer->backing;
|
|
|
|
}
|
|
|
|
|
2014-01-16 20:32:25 -08:00
|
|
|
void *
|
|
|
|
evas_filter_buffer_backing_steal(Evas_Filter_Context *ctx, int bufid)
|
|
|
|
{
|
|
|
|
Evas_Filter_Buffer *buffer;
|
|
|
|
|
2014-01-22 21:58:05 -08:00
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, NULL);
|
|
|
|
|
2014-01-16 20:32:25 -08:00
|
|
|
buffer = _filter_buffer_get(ctx, bufid);
|
|
|
|
if (!buffer) return NULL;
|
|
|
|
|
2014-01-22 21:58:05 -08:00
|
|
|
buffer->stolen = EINA_TRUE;
|
2014-03-06 16:36:16 -08:00
|
|
|
|
|
|
|
if (ctx->gl_engine)
|
2014-01-22 21:58:05 -08:00
|
|
|
return buffer->glimage;
|
2014-03-06 16:36:16 -08:00
|
|
|
|
|
|
|
if (ctx->async && buffer->backing)
|
|
|
|
buffer->backing->cache_entry.references++;
|
|
|
|
|
|
|
|
return buffer->backing;
|
2014-01-22 21:58:05 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
Eina_Bool
|
2014-03-06 16:36:16 -08:00
|
|
|
evas_filter_buffer_backing_release(Evas_Filter_Context *ctx,
|
|
|
|
void *stolen_buffer)
|
2014-01-22 21:58:05 -08:00
|
|
|
{
|
|
|
|
Evas_Filter_Buffer *fb;
|
|
|
|
Eina_List *li;
|
|
|
|
|
|
|
|
if (!stolen_buffer) return EINA_FALSE;
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, EINA_FALSE);
|
|
|
|
|
|
|
|
EINA_LIST_FOREACH(ctx->buffers, li, fb)
|
2014-01-16 22:05:23 -08:00
|
|
|
{
|
2014-03-06 16:36:16 -08:00
|
|
|
if (fb->backing == stolen_buffer)
|
2014-01-22 21:58:05 -08:00
|
|
|
{
|
|
|
|
fb->stolen = EINA_FALSE;
|
|
|
|
if (fb->delete_me)
|
|
|
|
{
|
|
|
|
ctx->buffers = eina_list_remove_list(ctx->buffers, li);
|
2014-01-23 17:54:51 -08:00
|
|
|
if (ctx->async)
|
|
|
|
{
|
|
|
|
if (fb->allocated)
|
2014-03-06 16:36:16 -08:00
|
|
|
evas_unref_queue_image_put(ctx->evas, stolen_buffer);
|
2014-01-23 17:54:51 -08:00
|
|
|
free(fb);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
_buffer_free(fb);
|
2014-01-22 21:58:05 -08:00
|
|
|
return EINA_TRUE;
|
|
|
|
}
|
|
|
|
return EINA_TRUE;
|
|
|
|
}
|
2014-02-06 23:06:46 -08:00
|
|
|
else if (fb->glimage == stolen_buffer)
|
|
|
|
{
|
|
|
|
fb->stolen = EINA_FALSE;
|
|
|
|
if (fb->delete_me)
|
|
|
|
{
|
2014-03-02 23:22:40 -08:00
|
|
|
ctx->buffers = eina_list_remove_list(ctx->buffers, li);
|
2014-03-06 16:36:16 -08:00
|
|
|
_buffer_free(fb);
|
2014-02-06 23:06:46 -08:00
|
|
|
}
|
|
|
|
return EINA_TRUE;
|
|
|
|
}
|
2014-01-16 22:05:23 -08:00
|
|
|
}
|
2014-01-22 21:58:05 -08:00
|
|
|
|
2014-01-23 17:54:51 -08:00
|
|
|
if (ctx->async)
|
2014-03-06 16:36:16 -08:00
|
|
|
evas_unref_queue_image_put(ctx->evas, stolen_buffer);
|
2014-02-06 23:06:46 -08:00
|
|
|
else if (ctx->gl_engine)
|
2014-03-02 02:08:22 -08:00
|
|
|
ctx->post_run.buffers_to_free =
|
|
|
|
eina_list_append(ctx->post_run.buffers_to_free, stolen_buffer);
|
2014-01-23 17:54:51 -08:00
|
|
|
else
|
2014-03-06 16:36:16 -08:00
|
|
|
_backing_free(ctx, stolen_buffer);
|
2014-01-23 17:54:51 -08:00
|
|
|
|
2014-01-22 21:58:05 -08:00
|
|
|
return EINA_TRUE;
|
2014-01-16 20:32:25 -08:00
|
|
|
}
|
|
|
|
|
2013-12-08 22:57:50 -08:00
|
|
|
static Evas_Filter_Command *
|
|
|
|
_command_new(Evas_Filter_Context *ctx, Evas_Filter_Mode mode,
|
|
|
|
Evas_Filter_Buffer *input, Evas_Filter_Buffer *mask,
|
|
|
|
Evas_Filter_Buffer *output)
|
|
|
|
{
|
|
|
|
Evas_Filter_Command *cmd;
|
|
|
|
|
|
|
|
cmd = calloc(1, sizeof(Evas_Filter_Command));
|
|
|
|
if (!cmd) return NULL;
|
|
|
|
|
|
|
|
cmd->id = ++(ctx->last_command_id);
|
|
|
|
cmd->ctx = ctx;
|
|
|
|
cmd->mode = mode;
|
|
|
|
cmd->input = input;
|
|
|
|
cmd->mask = mask;
|
|
|
|
cmd->output = output;
|
|
|
|
|
|
|
|
ctx->commands = eina_inlist_append(ctx->commands, EINA_INLIST_GET(cmd));
|
|
|
|
return cmd;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
_command_del(Evas_Filter_Context *ctx, Evas_Filter_Command *cmd)
|
|
|
|
{
|
|
|
|
if (!ctx || !cmd) return;
|
|
|
|
ctx->commands = eina_inlist_remove(ctx->commands, EINA_INLIST_GET(cmd));
|
|
|
|
switch (cmd->mode)
|
|
|
|
{
|
2014-02-10 22:56:31 -08:00
|
|
|
case EVAS_FILTER_MODE_CURVE: free(cmd->curve.data); break;
|
2013-12-08 22:57:50 -08:00
|
|
|
default: break;
|
|
|
|
}
|
|
|
|
free(cmd);
|
|
|
|
}
|
|
|
|
|
2014-01-22 23:54:50 -08:00
|
|
|
Evas_Filter_Command *
|
|
|
|
_evas_filter_command_get(Evas_Filter_Context *ctx, int cmdid)
|
2013-12-08 22:57:50 -08:00
|
|
|
{
|
|
|
|
Evas_Filter_Command *cmd;
|
|
|
|
|
|
|
|
if (cmdid <= 0) return NULL;
|
|
|
|
|
|
|
|
EINA_INLIST_FOREACH(ctx->commands, cmd)
|
|
|
|
if (cmd->id == cmdid) return cmd;
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2013-12-31 02:38:58 -08:00
|
|
|
Evas_Filter_Buffer *
|
|
|
|
evas_filter_temporary_buffer_get(Evas_Filter_Context *ctx, int w, int h,
|
|
|
|
Eina_Bool alpha_only)
|
2013-12-08 22:57:50 -08:00
|
|
|
{
|
|
|
|
Evas_Filter_Buffer *buf = NULL;
|
|
|
|
Eina_List *l;
|
|
|
|
|
|
|
|
EINA_LIST_FOREACH(ctx->buffers, l, buf)
|
|
|
|
{
|
|
|
|
if (buf->transient && !buf->locked && (buf->alpha_only == alpha_only))
|
|
|
|
{
|
|
|
|
if ((!w || (w == buf->w))
|
|
|
|
&& (!h || (h == buf->h)))
|
|
|
|
{
|
|
|
|
buf->locked = EINA_TRUE;
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-11 00:18:41 -07:00
|
|
|
if (ctx->running) // && ctx->async)
|
2014-02-06 18:22:36 -08:00
|
|
|
{
|
|
|
|
ERR("Can not create a new buffer from this thread!");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2013-12-08 22:57:50 -08:00
|
|
|
buf = _buffer_new(ctx, w, h, alpha_only);
|
|
|
|
buf->locked = EINA_TRUE;
|
2014-03-24 23:57:01 -07:00
|
|
|
DBG("Created temporary buffer: %d (%s)", buf->id, alpha_only ? "Alpha" : "RGBA");
|
2013-12-08 22:57:50 -08:00
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
_filter_buffer_unlock_all(Evas_Filter_Context *ctx)
|
|
|
|
{
|
|
|
|
Evas_Filter_Buffer *buf = NULL;
|
|
|
|
Eina_List *l;
|
|
|
|
|
|
|
|
EINA_LIST_FOREACH(ctx->buffers, l, buf)
|
|
|
|
buf->locked = EINA_FALSE;
|
|
|
|
}
|
|
|
|
|
2013-12-12 00:46:46 -08:00
|
|
|
int
|
|
|
|
evas_filter_command_fill_add(Evas_Filter_Context *ctx, void *draw_context,
|
|
|
|
int bufid)
|
|
|
|
{
|
|
|
|
Evas_Filter_Command *cmd;
|
|
|
|
Evas_Filter_Buffer *buf = NULL;
|
|
|
|
int R, G, B, A, cx, cy, cw, ch;
|
|
|
|
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, -1);
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(draw_context, -1);
|
|
|
|
|
|
|
|
buf = _filter_buffer_get(ctx, bufid);
|
|
|
|
if (!buf)
|
|
|
|
{
|
|
|
|
ERR("Buffer %d does not exist.", bufid);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2013-12-12 17:03:47 -08:00
|
|
|
cmd = _command_new(ctx, EVAS_FILTER_MODE_FILL, buf, NULL, buf);
|
2013-12-12 00:46:46 -08:00
|
|
|
if (!cmd) return -1;
|
|
|
|
|
|
|
|
ENFN->context_color_get(ENDT, draw_context, &R, &G, &B, &A);
|
|
|
|
DRAW_COLOR_SET(R, G, B, A);
|
|
|
|
|
|
|
|
ENFN->context_clip_get(ENDT, draw_context, &cx, &cy, &cw, &ch);
|
|
|
|
DRAW_CLIP_SET(cx, cy, cw, ch);
|
|
|
|
|
2014-03-20 20:20:11 -07:00
|
|
|
buf->dirty = EINA_TRUE;
|
2013-12-12 00:46:46 -08:00
|
|
|
return cmd->id;
|
|
|
|
}
|
|
|
|
|
2013-12-08 22:57:50 -08:00
|
|
|
int
|
|
|
|
evas_filter_command_blur_add(Evas_Filter_Context *ctx, void *drawctx,
|
|
|
|
int inbuf, int outbuf, Evas_Filter_Blur_Type type,
|
2014-03-11 02:21:46 -07:00
|
|
|
int dx, int dy, int ox, int oy, int count)
|
2013-12-08 22:57:50 -08:00
|
|
|
{
|
2014-02-07 19:15:35 -08:00
|
|
|
Evas_Filter_Command *cmd = NULL;
|
2013-12-08 22:57:50 -08:00
|
|
|
Evas_Filter_Buffer *in = NULL, *out = NULL, *tmp = NULL, *in_dy = NULL;
|
|
|
|
Evas_Filter_Buffer *out_dy = NULL, *out_dx = NULL;
|
|
|
|
Evas_Filter_Buffer *copybuf = NULL, *blur_out = NULL;
|
2014-03-20 20:20:11 -07:00
|
|
|
Eina_Bool copy_back = EINA_FALSE, blend = EINA_FALSE;
|
2013-12-08 22:57:50 -08:00
|
|
|
int R, G, B, A;
|
|
|
|
int ret = 0, id;
|
|
|
|
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, -1);
|
2013-12-12 00:46:46 -08:00
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(drawctx, -1);
|
2013-12-08 22:57:50 -08:00
|
|
|
|
2014-03-11 02:21:46 -07:00
|
|
|
if (dx < 0) dx = 0;
|
|
|
|
if (dy < 0) dy = 0;
|
2014-03-20 20:04:35 -07:00
|
|
|
if (!dx && !dy)
|
|
|
|
{
|
|
|
|
DBG("Changing 0px blur into simple blend");
|
|
|
|
return evas_filter_command_blend_add(ctx, drawctx, inbuf, outbuf, ox, oy, EVAS_FILTER_FILL_MODE_NONE);
|
|
|
|
}
|
2014-03-11 02:21:46 -07:00
|
|
|
|
2014-03-11 21:55:44 -07:00
|
|
|
in = _filter_buffer_get(ctx, inbuf);
|
|
|
|
if (!in)
|
|
|
|
{
|
|
|
|
ERR("Buffer %d does not exist [input].", inbuf);
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
out = _filter_buffer_get(ctx, outbuf);
|
|
|
|
if (!out)
|
|
|
|
{
|
|
|
|
ERR("Buffer %d does not exist [output].", outbuf);
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
2014-03-24 23:57:01 -07:00
|
|
|
if (in == out) out->dirty = EINA_FALSE;
|
2014-03-20 20:20:11 -07:00
|
|
|
blend = (out->dirty && !out->transient);
|
|
|
|
|
2013-12-08 22:57:50 -08:00
|
|
|
switch (type)
|
|
|
|
{
|
2014-03-11 02:21:46 -07:00
|
|
|
case EVAS_FILTER_BLUR_GAUSSIAN:
|
|
|
|
count = 1;
|
|
|
|
break;
|
|
|
|
|
2013-12-08 22:57:50 -08:00
|
|
|
case EVAS_FILTER_BLUR_BOX:
|
2014-03-11 02:21:46 -07:00
|
|
|
count = MIN(MAX(1, count), 6);
|
2013-12-08 22:57:50 -08:00
|
|
|
break;
|
2014-03-11 02:21:46 -07:00
|
|
|
|
|
|
|
case EVAS_FILTER_BLUR_DEFAULT:
|
|
|
|
|
|
|
|
/* In DEFAULT mode we cheat, depending on the size of the kernel:
|
|
|
|
* For 1px to 2px, use true Gaussian blur.
|
|
|
|
* For 3px to 6px, use two Box blurs.
|
|
|
|
* For more than 6px, use three Box blurs.
|
|
|
|
* This will give both nicer and MUCH faster results than Gaussian.
|
|
|
|
*
|
|
|
|
* NOTE: When implementing blur with GL shaders, other tricks will be
|
|
|
|
* needed, of course!
|
|
|
|
*/
|
|
|
|
{
|
2014-03-11 21:55:44 -07:00
|
|
|
const Eina_Bool alpha = in->alpha_only;
|
2014-03-11 02:21:46 -07:00
|
|
|
int tmp_out = outbuf;
|
|
|
|
int tmp_in = inbuf;
|
|
|
|
int tmp_ox = ox;
|
|
|
|
int tmp_oy = oy;
|
|
|
|
|
|
|
|
id = -1;
|
|
|
|
if (dx && dy)
|
|
|
|
{
|
2014-03-11 21:55:44 -07:00
|
|
|
tmp = evas_filter_temporary_buffer_get(ctx, 0, 0, alpha);
|
2014-03-11 02:21:46 -07:00
|
|
|
if (!tmp) goto fail;
|
|
|
|
tmp_in = tmp_out = tmp->id;
|
|
|
|
tmp_ox = tmp_oy = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dx)
|
|
|
|
{
|
|
|
|
if (dx <= 2)
|
|
|
|
type = EVAS_FILTER_BLUR_GAUSSIAN;
|
|
|
|
else
|
|
|
|
type = EVAS_FILTER_BLUR_BOX;
|
|
|
|
|
|
|
|
id = evas_filter_command_blur_add(ctx, drawctx, inbuf, tmp_out,
|
|
|
|
type, dx, 0, tmp_ox, tmp_oy, 0);
|
|
|
|
if (id < 0) goto fail;
|
|
|
|
cmd = _evas_filter_command_get(ctx, id);
|
|
|
|
cmd->blur.auto_count = EINA_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dy)
|
|
|
|
{
|
|
|
|
if (dy <= 2)
|
|
|
|
type = EVAS_FILTER_BLUR_GAUSSIAN;
|
|
|
|
else
|
|
|
|
type = EVAS_FILTER_BLUR_BOX;
|
|
|
|
|
2014-03-11 18:20:27 -07:00
|
|
|
id = evas_filter_command_blur_add(ctx, drawctx, tmp_in, outbuf,
|
2014-03-11 02:21:46 -07:00
|
|
|
type, 0, dy, ox, oy, 0);
|
|
|
|
if (id < 0) goto fail;
|
|
|
|
cmd = _evas_filter_command_get(ctx, id);
|
|
|
|
cmd->blur.auto_count = EINA_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return id;
|
|
|
|
}
|
2013-12-08 22:57:50 -08:00
|
|
|
break;
|
2014-03-11 02:21:46 -07:00
|
|
|
|
2013-12-08 22:57:50 -08:00
|
|
|
default:
|
2013-12-29 22:43:52 -08:00
|
|
|
CRI("Not implemented yet!");
|
2013-12-08 22:57:50 -08:00
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!in->alpha_only && out->alpha_only)
|
|
|
|
{
|
|
|
|
ERR("Output and input don't have the same format");
|
|
|
|
goto fail;
|
|
|
|
}
|
2014-03-20 20:20:11 -07:00
|
|
|
else if (blend || (in->alpha_only && !out->alpha_only))
|
2013-12-08 22:57:50 -08:00
|
|
|
{
|
2014-03-24 23:57:01 -07:00
|
|
|
DBG("Adding extra blending step %d --> %d (%s --> %s)", in->id, out->id,
|
|
|
|
in->alpha_only ? "Alpha" : "RGBA",
|
|
|
|
out->alpha_only ? "Alpha" : "RGBA");
|
2014-03-20 20:20:11 -07:00
|
|
|
blur_out = evas_filter_temporary_buffer_get(ctx, 0, 0, in->alpha_only);
|
2013-12-08 22:57:50 -08:00
|
|
|
if (!blur_out) goto fail;
|
2014-03-20 20:20:11 -07:00
|
|
|
blend = EINA_TRUE;
|
2013-12-08 22:57:50 -08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
blur_out = out;
|
|
|
|
|
|
|
|
if (dx && dy)
|
|
|
|
{
|
2013-12-31 02:38:58 -08:00
|
|
|
tmp = evas_filter_temporary_buffer_get(ctx, 0, 0, in->alpha_only);
|
2013-12-08 22:57:50 -08:00
|
|
|
if (!tmp) goto fail;
|
|
|
|
|
2014-03-20 20:20:11 -07:00
|
|
|
if (!blend && (ox || oy))
|
2013-12-08 22:57:50 -08:00
|
|
|
{
|
2013-12-31 02:38:58 -08:00
|
|
|
copybuf = evas_filter_temporary_buffer_get(ctx, 0, 0, in->alpha_only);
|
2014-02-13 19:45:55 -08:00
|
|
|
if (!copybuf) goto fail;
|
2013-12-08 22:57:50 -08:00
|
|
|
copy_back = EINA_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (in == blur_out)
|
|
|
|
{
|
|
|
|
// IN = OUT and 2-D blur. IN -blur-> TMP -blur-> IN.
|
|
|
|
out_dx = tmp;
|
|
|
|
in_dy = tmp;
|
|
|
|
out_dy = copybuf ? copybuf : in;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// IN != OUT and 2-D blur. IN -blur-> TMP -blur-> OUT.
|
|
|
|
out_dx = tmp;
|
|
|
|
in_dy = tmp;
|
|
|
|
out_dy = copybuf ? copybuf : blur_out;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (dx)
|
|
|
|
{
|
|
|
|
if ((in == blur_out) || ox || oy)
|
|
|
|
{
|
|
|
|
// IN = OUT and 1-D blur. IN -blur-> TMP -copy-> IN.
|
2013-12-31 02:38:58 -08:00
|
|
|
tmp = evas_filter_temporary_buffer_get(ctx, 0, 0, in->alpha_only);
|
2013-12-08 22:57:50 -08:00
|
|
|
if (!tmp) goto fail;
|
|
|
|
copy_back = EINA_TRUE;
|
|
|
|
copybuf = tmp;
|
|
|
|
out_dx = tmp;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// IN != OUT and 1-D blur. IN -blur-> OUT.
|
|
|
|
out_dx = blur_out;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if ((in == blur_out) || ox || oy)
|
|
|
|
{
|
|
|
|
// IN = OUT and 1-D blur. IN -blur-> TMP -copy-> IN.
|
2013-12-31 02:38:58 -08:00
|
|
|
tmp = evas_filter_temporary_buffer_get(ctx, 0, 0, in->alpha_only);
|
2013-12-08 22:57:50 -08:00
|
|
|
if (!tmp) goto fail;
|
|
|
|
copy_back = EINA_TRUE;
|
|
|
|
copybuf = tmp;
|
|
|
|
in_dy = in;
|
|
|
|
out_dy = tmp;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// IN != OUT and 1-D blur. IN -blur-> OUT.
|
|
|
|
in_dy = in;
|
|
|
|
out_dy = blur_out;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ENFN->context_color_get(ENDT, drawctx, &R, &G, &B, &A);
|
|
|
|
|
|
|
|
if (dx)
|
|
|
|
{
|
2014-03-06 17:59:54 -08:00
|
|
|
DBG("Add horizontal blur %d -> %d (%dpx)", in->id, out_dx->id, dx);
|
2013-12-08 22:57:50 -08:00
|
|
|
cmd = _command_new(ctx, EVAS_FILTER_MODE_BLUR, in, NULL, out_dx);
|
|
|
|
if (!cmd) goto fail;
|
|
|
|
cmd->blur.type = type;
|
|
|
|
cmd->blur.dx = dx;
|
|
|
|
cmd->blur.dy = 0;
|
2014-03-11 02:21:46 -07:00
|
|
|
cmd->blur.count = count;
|
2013-12-08 22:57:50 -08:00
|
|
|
DRAW_COLOR_SET(R, G, B, A);
|
|
|
|
ret = cmd->id;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dy)
|
|
|
|
{
|
2014-03-06 17:59:54 -08:00
|
|
|
DBG("Add vertical blur %d -> %d (%dpx)", in_dy->id, out_dy->id, dy);
|
2013-12-08 22:57:50 -08:00
|
|
|
cmd = _command_new(ctx, EVAS_FILTER_MODE_BLUR, in_dy, NULL, out_dy);
|
|
|
|
if (!cmd) goto fail;
|
|
|
|
cmd->blur.type = type;
|
|
|
|
cmd->blur.dx = 0;
|
|
|
|
cmd->blur.dy = dy;
|
2014-03-11 02:21:46 -07:00
|
|
|
cmd->blur.count = count;
|
2013-12-08 22:57:50 -08:00
|
|
|
DRAW_COLOR_SET(R, G, B, A);
|
|
|
|
if (ret <= 0) ret = cmd->id;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (copy_back)
|
|
|
|
{
|
2014-03-10 23:11:21 -07:00
|
|
|
int render_op;
|
|
|
|
|
2014-02-07 19:15:35 -08:00
|
|
|
if (!cmd) goto fail;
|
2014-03-06 17:59:54 -08:00
|
|
|
DBG("Add copy %d -> %d", copybuf->id, blur_out->id);
|
2013-12-08 22:57:50 -08:00
|
|
|
cmd->ENFN->context_color_set(cmd->ENDT, drawctx, 0, 0, 0, 255);
|
2014-03-10 23:11:21 -07:00
|
|
|
render_op = cmd->ENFN->context_render_op_get(cmd->ENDT, drawctx);
|
|
|
|
cmd->ENFN->context_render_op_set(cmd->ENDT, drawctx, EVAS_RENDER_COPY);
|
2013-12-31 00:51:09 -08:00
|
|
|
id = evas_filter_command_blend_add(ctx, drawctx, copybuf->id, blur_out->id, ox, oy, EVAS_FILTER_FILL_MODE_NONE);
|
2013-12-08 22:57:50 -08:00
|
|
|
cmd->ENFN->context_color_set(cmd->ENDT, drawctx, R, G, B, A);
|
2014-03-10 23:11:21 -07:00
|
|
|
cmd->ENFN->context_render_op_set(cmd->ENDT, drawctx, render_op);
|
2013-12-08 22:57:50 -08:00
|
|
|
if (id < 0) goto fail;
|
2014-02-19 03:03:20 -08:00
|
|
|
ox = oy = 0;
|
2013-12-08 22:57:50 -08:00
|
|
|
}
|
|
|
|
|
2014-03-20 20:20:11 -07:00
|
|
|
if (blend)
|
2013-12-08 22:57:50 -08:00
|
|
|
{
|
2014-03-20 20:20:11 -07:00
|
|
|
DBG("Add blend %d (%s) -> %d (%s)",
|
|
|
|
blur_out->id, blur_out->alpha_only ? "Alpha" : "RGBA",
|
|
|
|
out->id, out->alpha_only ? "Alpha" : "RGBA");
|
2013-12-31 00:51:09 -08:00
|
|
|
id = evas_filter_command_blend_add(ctx, drawctx, blur_out->id, out->id, ox, oy, EVAS_FILTER_FILL_MODE_NONE);
|
2013-12-08 22:57:50 -08:00
|
|
|
if (id < 0) goto fail;
|
|
|
|
}
|
|
|
|
|
2014-03-20 20:20:11 -07:00
|
|
|
out->dirty = EINA_TRUE;
|
2013-12-08 22:57:50 -08:00
|
|
|
_filter_buffer_unlock_all(ctx);
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
fail:
|
|
|
|
ERR("Failed to add blur");
|
|
|
|
_filter_buffer_unlock_all(ctx);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
evas_filter_command_blend_add(Evas_Filter_Context *ctx, void *drawctx,
|
2013-12-31 00:51:09 -08:00
|
|
|
int inbuf, int outbuf, int ox, int oy,
|
|
|
|
Evas_Filter_Fill_Mode fillmode)
|
2013-12-08 22:57:50 -08:00
|
|
|
{
|
|
|
|
Evas_Filter_Command *cmd;
|
|
|
|
Evas_Filter_Buffer *in, *out;
|
|
|
|
int R, G, B, A;
|
|
|
|
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, -1);
|
|
|
|
|
|
|
|
if (inbuf == outbuf)
|
|
|
|
{
|
|
|
|
DBG("Skipping NOP blend operation %d --> %d", inbuf, outbuf);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
in = _filter_buffer_get(ctx, inbuf);
|
|
|
|
if (!in)
|
|
|
|
{
|
|
|
|
ERR("Buffer %d does not exist [input].", inbuf);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
out = _filter_buffer_get(ctx, outbuf);
|
|
|
|
if (!out)
|
|
|
|
{
|
|
|
|
ERR("Buffer %d does not exist [output].", outbuf);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
cmd = _command_new(ctx, EVAS_FILTER_MODE_BLEND, in, NULL, out);
|
|
|
|
if (!cmd) return -1;
|
|
|
|
|
|
|
|
ENFN->context_color_get(ENDT, drawctx, &R, &G, &B, &A);
|
|
|
|
DRAW_COLOR_SET(R, G, B, A);
|
2013-12-31 00:51:09 -08:00
|
|
|
DRAW_FILL_SET(fillmode);
|
2013-12-08 22:57:50 -08:00
|
|
|
cmd->draw.ox = ox;
|
|
|
|
cmd->draw.oy = oy;
|
|
|
|
cmd->draw.render_op = ENFN->context_render_op_get(ENDT, drawctx);
|
2014-01-02 22:51:17 -08:00
|
|
|
cmd->draw.clip_use =
|
|
|
|
ENFN->context_clip_get(ENDT, drawctx,
|
|
|
|
&cmd->draw.clip.x, &cmd->draw.clip.y,
|
|
|
|
&cmd->draw.clip.w, &cmd->draw.clip.h);
|
2013-12-08 22:57:50 -08:00
|
|
|
|
2014-01-22 23:54:50 -08:00
|
|
|
if (cmd->draw.clip_use)
|
|
|
|
DBG("Draw clip: %d,%d,%d,%d", cmd->draw.clip.x, cmd->draw.clip.y,
|
|
|
|
cmd->draw.clip.w, cmd->draw.clip.h);
|
|
|
|
|
2014-03-20 20:20:11 -07:00
|
|
|
out->dirty = EINA_TRUE;
|
2013-12-08 22:57:50 -08:00
|
|
|
return cmd->id;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
evas_filter_command_grow_add(Evas_Filter_Context *ctx, void *draw_context,
|
|
|
|
int inbuf, int outbuf, int radius, Eina_Bool smooth)
|
|
|
|
{
|
2014-02-19 02:38:58 -08:00
|
|
|
int blurcmd, threshcmd, blendcmd, tmin = 0, growbuf;
|
2013-12-08 22:57:50 -08:00
|
|
|
int diam = abs(radius) * 2 + 1;
|
|
|
|
DATA8 curve[256] = {0};
|
2014-03-20 20:20:11 -07:00
|
|
|
Evas_Filter_Buffer *tmp = NULL, *in, *out;
|
2013-12-08 22:57:50 -08:00
|
|
|
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, -1);
|
|
|
|
|
2014-03-20 20:04:35 -07:00
|
|
|
if (!radius)
|
|
|
|
{
|
|
|
|
DBG("Changing 0px grow into simple blend");
|
|
|
|
return evas_filter_command_blend_add(ctx, draw_context, inbuf, outbuf, 0, 0, EVAS_FILTER_FILL_MODE_NONE);
|
|
|
|
}
|
|
|
|
|
2014-02-19 02:38:58 -08:00
|
|
|
in = _filter_buffer_get(ctx, inbuf);
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(in, -1);
|
|
|
|
|
|
|
|
if (inbuf != outbuf)
|
|
|
|
{
|
|
|
|
tmp = evas_filter_temporary_buffer_get(ctx, in->w, in->h, in->alpha_only);
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(tmp, -1);
|
|
|
|
growbuf = tmp->id;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
growbuf = outbuf;
|
|
|
|
|
|
|
|
blurcmd = evas_filter_command_blur_add(ctx, draw_context, inbuf, growbuf,
|
2013-12-08 22:57:50 -08:00
|
|
|
EVAS_FILTER_BLUR_DEFAULT,
|
2014-03-11 02:21:46 -07:00
|
|
|
abs(radius), abs(radius), 0, 0, 0);
|
2013-12-08 22:57:50 -08:00
|
|
|
if (blurcmd < 0) return -1;
|
|
|
|
|
|
|
|
if (diam > 255) diam = 255;
|
|
|
|
if (radius > 0)
|
|
|
|
tmin = 255 / diam;
|
|
|
|
else if (radius < 0)
|
|
|
|
tmin = 256 - (255 / diam);
|
|
|
|
|
|
|
|
if (!smooth)
|
|
|
|
memset(curve + tmin, 255, 256 - tmin);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int k, start, end, range;
|
|
|
|
|
|
|
|
// This is pretty experimental.
|
|
|
|
range = MAX(2, 12 - radius);
|
|
|
|
start = ((tmin > range) ? (tmin - range) : 0);
|
|
|
|
end = ((tmin < (256 - range)) ? (tmin + range) : 256);
|
|
|
|
|
|
|
|
for (k = start; k < end; k++)
|
|
|
|
curve[k] = ((k - start) * 255) / (end - start);
|
|
|
|
if (end < 256)
|
|
|
|
memset(curve + end, 255, 256 - end);
|
|
|
|
}
|
|
|
|
|
2014-03-20 20:20:11 -07:00
|
|
|
out = _filter_buffer_get(ctx, growbuf);
|
|
|
|
if (!out) return -1;
|
|
|
|
out->dirty = EINA_TRUE;
|
|
|
|
if (growbuf != outbuf)
|
|
|
|
{
|
|
|
|
out = _filter_buffer_get(ctx, growbuf);
|
|
|
|
if (!out) return -1;
|
|
|
|
out->dirty = EINA_TRUE;
|
|
|
|
}
|
|
|
|
|
2014-02-19 02:38:58 -08:00
|
|
|
threshcmd = evas_filter_command_curve_add(ctx, draw_context, growbuf, growbuf,
|
2013-12-08 22:57:50 -08:00
|
|
|
curve, EVAS_FILTER_CHANNEL_ALPHA);
|
|
|
|
if (threshcmd < 0)
|
|
|
|
{
|
2014-01-22 23:54:50 -08:00
|
|
|
_command_del(ctx, _evas_filter_command_get(ctx, blurcmd));
|
2013-12-08 22:57:50 -08:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2014-02-19 02:38:58 -08:00
|
|
|
if (tmp)
|
|
|
|
{
|
|
|
|
blendcmd = evas_filter_command_blend_add(ctx, draw_context, tmp->id,
|
|
|
|
outbuf, 0, 0,
|
|
|
|
EVAS_FILTER_FILL_MODE_NONE);
|
|
|
|
if (blendcmd < 0)
|
|
|
|
{
|
|
|
|
_command_del(ctx, _evas_filter_command_get(ctx, threshcmd));
|
|
|
|
_command_del(ctx, _evas_filter_command_get(ctx, blurcmd));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-08 22:57:50 -08:00
|
|
|
return blurcmd;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
evas_filter_command_curve_add(Evas_Filter_Context *ctx,
|
|
|
|
void *draw_context EINA_UNUSED,
|
|
|
|
int inbuf, int outbuf, DATA8 *curve,
|
|
|
|
Evas_Filter_Channel channel)
|
|
|
|
{
|
|
|
|
Evas_Filter_Command *cmd;
|
|
|
|
Evas_Filter_Buffer *in, *out;
|
|
|
|
DATA8 *copy;
|
|
|
|
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, -1);
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(curve, -1);
|
|
|
|
|
|
|
|
in = _filter_buffer_get(ctx, inbuf);
|
|
|
|
out = _filter_buffer_get(ctx, outbuf);
|
|
|
|
if (!in || !out)
|
|
|
|
{
|
|
|
|
ERR("Invalid buffer id: input %d [%p], output %d [%p]",
|
|
|
|
inbuf, in, outbuf, out);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (in->alpha_only != out->alpha_only)
|
|
|
|
{
|
|
|
|
ERR("Incompatible formats for color curves");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
copy = malloc(256 * sizeof(DATA8));
|
|
|
|
if (!copy) return -1;
|
|
|
|
|
|
|
|
cmd = _command_new(ctx, EVAS_FILTER_MODE_CURVE, in, NULL, out);
|
2014-02-13 01:57:01 -08:00
|
|
|
if (!cmd)
|
|
|
|
{
|
|
|
|
free(copy);
|
|
|
|
return -1;
|
|
|
|
}
|
2013-12-08 22:57:50 -08:00
|
|
|
|
|
|
|
memcpy(copy, curve, 256 * sizeof(DATA8));
|
|
|
|
cmd->curve.data = copy;
|
|
|
|
cmd->curve.channel = channel;
|
|
|
|
|
2014-03-20 20:20:11 -07:00
|
|
|
out->dirty = EINA_TRUE;
|
2013-12-08 22:57:50 -08:00
|
|
|
return cmd->id;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
evas_filter_command_displacement_map_add(Evas_Filter_Context *ctx,
|
|
|
|
void *draw_context EINA_UNUSED,
|
|
|
|
int inbuf, int outbuf, int dispbuf,
|
|
|
|
Evas_Filter_Displacement_Flags flags,
|
2013-12-31 00:51:09 -08:00
|
|
|
int intensity,
|
|
|
|
Evas_Filter_Fill_Mode fillmode)
|
2013-12-08 22:57:50 -08:00
|
|
|
{
|
|
|
|
Evas_Filter_Command *cmd;
|
|
|
|
Evas_Filter_Buffer *in, *out, *map, *tmp = NULL, *disp_out;
|
|
|
|
int cmdid = -1;
|
|
|
|
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, -1);
|
|
|
|
EINA_SAFETY_ON_FALSE_RETURN_VAL(intensity >= 0, EINA_FALSE);
|
|
|
|
|
|
|
|
in = _filter_buffer_get(ctx, inbuf);
|
|
|
|
out = _filter_buffer_get(ctx, outbuf);
|
|
|
|
map = _filter_buffer_get(ctx, dispbuf);
|
|
|
|
if (!in || !out || !map)
|
|
|
|
{
|
|
|
|
ERR("Invalid buffer id: input %d [%p], output %d [%p], map %d [%p]",
|
|
|
|
inbuf, in, outbuf, out, dispbuf, map);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (in->alpha_only != out->alpha_only)
|
|
|
|
{
|
|
|
|
ERR("Incompatible formats for displacement map");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (in == out)
|
|
|
|
{
|
2013-12-31 02:38:58 -08:00
|
|
|
tmp = evas_filter_temporary_buffer_get(ctx, in->w, in->h, in->alpha_only);
|
2013-12-08 22:57:50 -08:00
|
|
|
if (!tmp) return -1;
|
|
|
|
disp_out = tmp;
|
|
|
|
}
|
|
|
|
else disp_out = out;
|
|
|
|
|
|
|
|
cmd = _command_new(ctx, EVAS_FILTER_MODE_DISPLACE, in, map, disp_out);
|
|
|
|
if (!cmd) goto end;
|
|
|
|
|
2013-12-31 00:51:09 -08:00
|
|
|
DRAW_FILL_SET(fillmode);
|
2014-01-06 17:16:39 -08:00
|
|
|
cmd->displacement.flags = flags & EVAS_FILTER_DISPLACE_BITMASK;
|
2013-12-08 22:57:50 -08:00
|
|
|
cmd->displacement.intensity = intensity;
|
2014-01-06 18:03:46 -08:00
|
|
|
cmd->draw.render_op = ENFN->context_render_op_get(ENDT, draw_context);
|
2013-12-08 22:57:50 -08:00
|
|
|
cmdid = cmd->id;
|
|
|
|
|
|
|
|
if (tmp)
|
|
|
|
{
|
|
|
|
if (evas_filter_command_blend_add(ctx, draw_context, disp_out->id,
|
2013-12-31 00:51:09 -08:00
|
|
|
out->id, 0, 0,
|
|
|
|
EVAS_FILTER_FILL_MODE_NONE) < 0)
|
2013-12-08 22:57:50 -08:00
|
|
|
{
|
2014-01-22 23:54:50 -08:00
|
|
|
_command_del(ctx, _evas_filter_command_get(ctx, cmdid));
|
2013-12-08 22:57:50 -08:00
|
|
|
cmdid = -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-20 20:20:11 -07:00
|
|
|
out->dirty = EINA_TRUE;
|
|
|
|
|
2013-12-08 22:57:50 -08:00
|
|
|
end:
|
|
|
|
_filter_buffer_unlock_all(ctx);
|
|
|
|
return cmdid;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
evas_filter_command_mask_add(Evas_Filter_Context *ctx, void *draw_context,
|
2013-12-31 00:51:09 -08:00
|
|
|
int inbuf, int maskbuf, int outbuf,
|
|
|
|
Evas_Filter_Fill_Mode fillmode)
|
2013-12-08 22:57:50 -08:00
|
|
|
{
|
|
|
|
Evas_Filter_Command *cmd;
|
|
|
|
Evas_Filter_Buffer *in, *out, *mask;
|
|
|
|
int cmdid = -1, render_op;
|
|
|
|
int R, G, B, A;
|
|
|
|
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, -1);
|
|
|
|
|
|
|
|
render_op = ENFN->context_render_op_get(ENDT, draw_context);
|
|
|
|
ENFN->context_color_get(ENDT, draw_context, &R, &G, &B, &A);
|
|
|
|
|
|
|
|
in = _filter_buffer_get(ctx, inbuf);
|
|
|
|
out = _filter_buffer_get(ctx, outbuf);
|
|
|
|
mask = _filter_buffer_get(ctx, maskbuf);
|
|
|
|
if (!in || !out || !mask)
|
|
|
|
{
|
|
|
|
ERR("Invalid buffer id: input %d [%p], output %d [%p], mask %d [%p]",
|
|
|
|
inbuf, in, outbuf, out, maskbuf, mask);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
cmd = _command_new(ctx, EVAS_FILTER_MODE_MASK, in, mask, out);
|
|
|
|
if (!cmd) goto end;
|
|
|
|
|
|
|
|
cmd->draw.render_op = render_op;
|
|
|
|
DRAW_COLOR_SET(R, G, B, A);
|
2013-12-31 00:51:09 -08:00
|
|
|
DRAW_FILL_SET(fillmode);
|
2013-12-08 22:57:50 -08:00
|
|
|
|
|
|
|
cmdid = cmd->id;
|
2014-03-20 20:20:11 -07:00
|
|
|
out->dirty = EINA_TRUE;
|
2013-12-08 22:57:50 -08:00
|
|
|
|
|
|
|
end:
|
|
|
|
_filter_buffer_unlock_all(ctx);
|
|
|
|
return cmdid;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
evas_filter_command_bump_map_add(Evas_Filter_Context *ctx,
|
|
|
|
void *draw_context EINA_UNUSED,
|
|
|
|
int inbuf, int bumpbuf, int outbuf,
|
|
|
|
float xyangle, float zangle, float elevation,
|
|
|
|
float sf,
|
|
|
|
DATA32 black, DATA32 color, DATA32 white,
|
2013-12-31 00:51:09 -08:00
|
|
|
Evas_Filter_Bump_Flags flags,
|
|
|
|
Evas_Filter_Fill_Mode fillmode)
|
2013-12-08 22:57:50 -08:00
|
|
|
{
|
|
|
|
Evas_Filter_Command *cmd;
|
|
|
|
Evas_Filter_Buffer *in, *out, *bumpmap;
|
|
|
|
int cmdid = -1;
|
|
|
|
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, -1);
|
|
|
|
|
|
|
|
in = _filter_buffer_get(ctx, inbuf);
|
|
|
|
out = _filter_buffer_get(ctx, outbuf);
|
|
|
|
bumpmap = _filter_buffer_get(ctx, bumpbuf);
|
|
|
|
if (!in || !out || !bumpmap)
|
|
|
|
{
|
|
|
|
ERR("Invalid buffer id: input %d [%p], output %d [%p], bumpmap %d [%p]",
|
|
|
|
inbuf, in, outbuf, out, bumpbuf, bumpmap);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME: Must ensure in != out
|
2013-12-29 22:43:52 -08:00
|
|
|
if (in == out) CRI("Not acceptable");
|
|
|
|
if (bumpmap == out) CRI("Not acceptable");
|
2013-12-08 22:57:50 -08:00
|
|
|
|
|
|
|
cmd = _command_new(ctx, EVAS_FILTER_MODE_BUMP, in, bumpmap, out);
|
|
|
|
if (!cmd) goto end;
|
|
|
|
|
2013-12-31 00:51:09 -08:00
|
|
|
DRAW_FILL_SET(fillmode);
|
2013-12-08 22:57:50 -08:00
|
|
|
cmd->bump.xyangle = xyangle;
|
|
|
|
cmd->bump.zangle = zangle;
|
|
|
|
cmd->bump.specular_factor = sf;
|
|
|
|
cmd->bump.dark = black;
|
|
|
|
cmd->bump.color = color;
|
|
|
|
cmd->bump.white = white;
|
|
|
|
cmd->bump.elevation = elevation;
|
|
|
|
cmd->bump.compensate = !!(flags & EVAS_FILTER_BUMP_COMPENSATE);
|
|
|
|
cmdid = cmd->id;
|
|
|
|
|
2014-03-20 20:20:11 -07:00
|
|
|
out->dirty = EINA_TRUE;
|
|
|
|
|
2013-12-08 22:57:50 -08:00
|
|
|
end:
|
|
|
|
_filter_buffer_unlock_all(ctx);
|
|
|
|
return cmdid;
|
|
|
|
}
|
|
|
|
|
2014-01-06 23:44:10 -08:00
|
|
|
int
|
2014-01-07 01:38:22 -08:00
|
|
|
evas_filter_command_transform_add(Evas_Filter_Context *ctx,
|
|
|
|
void *draw_context EINA_UNUSED,
|
2014-01-06 23:44:10 -08:00
|
|
|
int inbuf, int outbuf,
|
2014-01-07 01:38:22 -08:00
|
|
|
Evas_Filter_Transform_Flags flags,
|
|
|
|
int ox, int oy)
|
2014-01-06 23:44:10 -08:00
|
|
|
{
|
|
|
|
Evas_Filter_Command *cmd;
|
|
|
|
Evas_Filter_Buffer *in, *out;
|
|
|
|
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, -1);
|
|
|
|
|
|
|
|
in = _filter_buffer_get(ctx, inbuf);
|
|
|
|
out = _filter_buffer_get(ctx, outbuf);
|
|
|
|
if (!in || !out)
|
|
|
|
{
|
|
|
|
ERR("Invalid buffer id: input %d [%p], output %d [%p]",
|
|
|
|
inbuf, in, outbuf, out);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (in->alpha_only != out->alpha_only)
|
|
|
|
{
|
|
|
|
CRI("Incompatible buffer formats");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
cmd = _command_new(ctx, EVAS_FILTER_MODE_TRANSFORM, in, NULL, out);
|
|
|
|
if (!cmd) return -1;
|
|
|
|
|
|
|
|
cmd->transform.flags = flags;
|
2014-01-07 01:38:22 -08:00
|
|
|
cmd->draw.ox = ox;
|
|
|
|
cmd->draw.oy = oy;
|
2014-01-06 23:44:10 -08:00
|
|
|
|
2014-03-20 20:20:11 -07:00
|
|
|
out->dirty = EINA_TRUE;
|
|
|
|
|
2014-01-06 23:44:10 -08:00
|
|
|
return cmd->id;
|
|
|
|
}
|
|
|
|
|
2013-12-12 00:46:46 -08:00
|
|
|
static Eina_Bool
|
|
|
|
_fill_cpu(Evas_Filter_Command *cmd)
|
|
|
|
{
|
2013-12-12 17:03:47 -08:00
|
|
|
Evas_Filter_Buffer *fb = cmd->output;
|
2013-12-12 00:46:46 -08:00
|
|
|
int step = fb->alpha_only ? sizeof(DATA8) : sizeof(DATA32);
|
2014-01-02 01:44:01 -08:00
|
|
|
int x = MAX(0, cmd->draw.clip.x);
|
|
|
|
int y = MAX(0, cmd->draw.clip.y);
|
2014-03-03 19:05:44 -08:00
|
|
|
DATA8 *ptr = ((RGBA_Image *) fb->backing)->image.data8;
|
2013-12-12 00:46:46 -08:00
|
|
|
int w, h, k, j;
|
|
|
|
|
2014-01-02 01:44:01 -08:00
|
|
|
if (!cmd->draw.clip_mode_lrtb)
|
|
|
|
{
|
|
|
|
if (cmd->draw.clip.w)
|
|
|
|
w = MIN(cmd->draw.clip.w, fb->w - x);
|
|
|
|
else
|
|
|
|
w = fb->w - x;
|
|
|
|
if (cmd->draw.clip.h)
|
|
|
|
h = MIN(cmd->draw.clip.h, fb->h - y);
|
|
|
|
else
|
|
|
|
h = fb->h - y;
|
|
|
|
}
|
2013-12-12 00:46:46 -08:00
|
|
|
else
|
2014-01-02 01:44:01 -08:00
|
|
|
{
|
|
|
|
x = MAX(0, cmd->draw.clip.l);
|
|
|
|
y = MAX(0, cmd->draw.clip.t);
|
|
|
|
w = CLAMP(0, fb->w - x - cmd->draw.clip.r, fb->w - x);
|
|
|
|
h = CLAMP(0, fb->h - y - cmd->draw.clip.b, fb->h - y);
|
|
|
|
}
|
2013-12-12 00:46:46 -08:00
|
|
|
|
|
|
|
ptr += y * step * fb->w;
|
|
|
|
if ((fb->alpha_only)
|
|
|
|
|| (!cmd->draw.R && !cmd->draw.G && !cmd->draw.B && !cmd->draw.A)
|
|
|
|
|| ((cmd->draw.R == 0xff) && (cmd->draw.G == 0xff)
|
|
|
|
&& (cmd->draw.B == 0xff) && (cmd->draw.A == 0xff)))
|
|
|
|
{
|
|
|
|
for (k = 0; k < h; k++)
|
|
|
|
{
|
|
|
|
memset(ptr + (x * step), cmd->draw.A, step * w);
|
|
|
|
ptr += step * fb->w;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
DATA32 *dst = ((DATA32 *) ptr) + x;
|
|
|
|
DATA32 color = ARGB_JOIN(cmd->draw.A, cmd->draw.R, cmd->draw.G, cmd->draw.B);
|
|
|
|
for (k = 0; k < h; k++)
|
|
|
|
{
|
|
|
|
for (j = 0; j < w; j++)
|
|
|
|
*dst++ = color;
|
2014-01-02 01:44:01 -08:00
|
|
|
dst += fb->w - w;
|
2013-12-12 00:46:46 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return EINA_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
Evas_Filter_Apply_Func
|
|
|
|
evas_filter_fill_cpu_func_get(Evas_Filter_Command *cmd)
|
|
|
|
{
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(cmd, NULL);
|
2013-12-12 17:03:47 -08:00
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(cmd->output, NULL);
|
2013-12-12 00:46:46 -08:00
|
|
|
return _fill_cpu;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-01-16 22:05:23 -08:00
|
|
|
/* Final target */
|
|
|
|
Eina_Bool
|
|
|
|
evas_filter_target_set(Evas_Filter_Context *ctx, void *draw_context,
|
|
|
|
void *surface, int x, int y)
|
|
|
|
{
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, EINA_FALSE);
|
|
|
|
|
2014-03-02 01:39:08 -08:00
|
|
|
ctx->target.bufid = evas_filter_buffer_image_new(ctx, surface);
|
|
|
|
ctx->target.x = x;
|
|
|
|
ctx->target.y = y;
|
|
|
|
ctx->target.clip_use = ENFN->context_clip_get
|
|
|
|
(ENDT, draw_context, &ctx->target.cx, &ctx->target.cy,
|
|
|
|
&ctx->target.cw, &ctx->target.ch);
|
2014-06-10 23:59:31 -07:00
|
|
|
ctx->target.color_use = ENFN->context_multiplier_get
|
|
|
|
(ENDT, draw_context, &ctx->target.r, &ctx->target.g,
|
|
|
|
&ctx->target.b, &ctx->target.a);
|
|
|
|
if (ctx->target.r == 255 && ctx->target.g == 255 &&
|
|
|
|
ctx->target.b == 255 && ctx->target.a == 255)
|
|
|
|
ctx->target.color_use = EINA_FALSE;
|
2014-03-02 01:39:08 -08:00
|
|
|
|
|
|
|
if (ctx->gl_engine)
|
2014-01-16 22:05:23 -08:00
|
|
|
{
|
|
|
|
// Since GL has sync rendering, draw_context is safe to keep around
|
2014-03-06 16:36:16 -08:00
|
|
|
Evas_Filter_Buffer *fb;
|
2014-01-16 22:05:23 -08:00
|
|
|
|
|
|
|
ctx->target.context = draw_context;
|
2014-03-06 16:36:16 -08:00
|
|
|
|
|
|
|
fb = _filter_buffer_get(ctx, EVAS_FILTER_BUFFER_OUTPUT_ID);
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(fb, EINA_FALSE);
|
|
|
|
|
|
|
|
fb->glimage = ENFN->image_new_from_data
|
|
|
|
(ENDT, fb->w, fb->h, fb->backing->image.data, EINA_TRUE,
|
|
|
|
fb->backing->cache_entry.space);
|
|
|
|
|
|
|
|
DBG("Set target as #%d (%p) and output #%d (%p, gl %p)",
|
|
|
|
ctx->target.bufid, surface, fb->id, fb->backing, fb->glimage);
|
2014-01-16 22:05:23 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
return EINA_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static Eina_Bool
|
|
|
|
_filter_target_render(Evas_Filter_Context *ctx)
|
|
|
|
{
|
|
|
|
Evas_Filter_Buffer *src, *dst;
|
2014-03-02 01:39:08 -08:00
|
|
|
void *drawctx, *image, *surface;
|
|
|
|
int cx, cy, cw, ch;
|
|
|
|
Eina_Bool use_clip = EINA_FALSE;
|
2014-01-16 22:05:23 -08:00
|
|
|
|
|
|
|
EINA_SAFETY_ON_FALSE_RETURN_VAL(ctx->target.bufid, EINA_FALSE);
|
|
|
|
|
2014-02-03 19:32:15 -08:00
|
|
|
src = _filter_buffer_get(ctx, EVAS_FILTER_BUFFER_OUTPUT_ID);
|
2014-01-16 22:05:23 -08:00
|
|
|
dst = _filter_buffer_get(ctx, ctx->target.bufid);
|
2014-03-02 01:39:08 -08:00
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(src, EINA_FALSE);
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(dst, EINA_FALSE);
|
|
|
|
|
|
|
|
if (!ctx->gl_engine)
|
|
|
|
{
|
|
|
|
drawctx = ENFN->context_new(ENDT);
|
|
|
|
surface = dst->backing;
|
|
|
|
image = src->backing;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
drawctx = ctx->target.context;
|
|
|
|
surface = dst->glimage;
|
2014-03-06 16:36:16 -08:00
|
|
|
if (src->glimage)
|
|
|
|
{
|
|
|
|
DBG("Using glimage from output buffer.");
|
|
|
|
if (src->backing)
|
|
|
|
ENFN->image_data_put(ENDT, src->glimage, src->backing->image.data);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
RGBA_Image *im = src->backing;
|
|
|
|
|
|
|
|
DBG("Creating glimage from output buffer.");
|
|
|
|
src->glimage = ENFN->image_new_from_data(ENDT, src->w, src->h,
|
|
|
|
im->image.data, EINA_TRUE,
|
|
|
|
EVAS_COLORSPACE_ARGB8888);
|
|
|
|
}
|
2014-03-02 01:39:08 -08:00
|
|
|
image = src->glimage;
|
|
|
|
}
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(image, EINA_FALSE);
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(surface, EINA_FALSE);
|
2014-01-16 22:05:23 -08:00
|
|
|
|
2014-03-02 01:39:08 -08:00
|
|
|
if (ctx->target.clip_use)
|
|
|
|
{
|
|
|
|
use_clip = ENFN->context_clip_get(ENDT, drawctx, &cx, &cy, &cw, &ch);
|
|
|
|
ENFN->context_clip_set(ENDT, drawctx, ctx->target.cx, ctx->target.cy,
|
|
|
|
ctx->target.cw, ctx->target.ch);
|
|
|
|
}
|
2014-01-16 22:05:23 -08:00
|
|
|
|
2014-06-10 23:59:31 -07:00
|
|
|
if (ctx->target.color_use)
|
|
|
|
{
|
|
|
|
ENFN->context_multiplier_set(ENDT, drawctx,
|
|
|
|
ctx->target.r, ctx->target.g,
|
|
|
|
ctx->target.b, ctx->target.a);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ENFN->context_multiplier_unset(ENDT, drawctx);
|
|
|
|
}
|
|
|
|
|
2014-03-02 01:39:08 -08:00
|
|
|
ENFN->image_draw(ENDT, drawctx, surface, image,
|
|
|
|
0, 0, src->w, src->h,
|
|
|
|
ctx->target.x, ctx->target.y, src->w, src->h,
|
|
|
|
EINA_TRUE, EINA_FALSE);
|
2014-01-16 22:05:23 -08:00
|
|
|
|
2014-03-02 01:39:08 -08:00
|
|
|
if (!ctx->gl_engine)
|
|
|
|
ENFN->context_free(ENDT, drawctx);
|
|
|
|
else if (use_clip)
|
|
|
|
ENFN->context_clip_set(ENDT, drawctx, cx, cy, cw, ch);
|
|
|
|
else
|
|
|
|
ENFN->context_clip_unset(ENDT, drawctx);
|
|
|
|
|
|
|
|
return EINA_TRUE;
|
2014-01-16 22:05:23 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-01-16 20:32:25 -08:00
|
|
|
/* Font drawing stuff */
|
|
|
|
Eina_Bool
|
|
|
|
evas_filter_font_draw(Evas_Filter_Context *ctx, void *draw_context, int bufid,
|
|
|
|
Evas_Font_Set *font, int x, int y,
|
|
|
|
Evas_Text_Props *text_props, Eina_Bool do_async)
|
|
|
|
{
|
|
|
|
Eina_Bool async_unref;
|
|
|
|
Evas_Filter_Buffer *fb;
|
|
|
|
void *surface;
|
|
|
|
|
|
|
|
fb = _filter_buffer_get(ctx, bufid);
|
|
|
|
if (!fb) return EINA_FALSE;
|
|
|
|
|
|
|
|
surface = fb->backing;
|
|
|
|
if (!surface) return EINA_FALSE;
|
|
|
|
|
|
|
|
if (!ctx->gl_engine)
|
|
|
|
{
|
|
|
|
// Copied from evas_font_draw_async_check
|
|
|
|
async_unref = ENFN->font_draw(ENDT, draw_context, surface,
|
|
|
|
font, x, y, fb->w, fb->h, fb->w, fb->h,
|
|
|
|
text_props, do_async);
|
|
|
|
if (do_async && async_unref)
|
|
|
|
{
|
|
|
|
evas_common_font_glyphs_ref(text_props->glyphs);
|
|
|
|
evas_unref_queue_glyph_put(ctx->evas, text_props->glyphs);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// FIXME/GL: Render in software only.
|
|
|
|
// Copied from eng_font_draw in the software engine.
|
|
|
|
|
|
|
|
if (do_async) WRN("Async flag is ignored here!");
|
|
|
|
evas_common_font_draw_prepare(text_props);
|
|
|
|
evas_common_font_draw(surface, draw_context, x, y, text_props->glyphs);
|
|
|
|
evas_common_cpu_end_opt();
|
|
|
|
}
|
|
|
|
|
|
|
|
return EINA_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-03-17 00:10:03 -07:00
|
|
|
/* Image draw: glReadPixels or just use SW buffer */
|
|
|
|
Eina_Bool
|
|
|
|
evas_filter_image_draw(Evas_Filter_Context *ctx, void *draw_context, int bufid,
|
|
|
|
void *image, Eina_Bool do_async)
|
|
|
|
{
|
|
|
|
int w = 0, h = 0;
|
|
|
|
|
|
|
|
ENFN->image_size_get(ENDT, image, &w, &h);
|
|
|
|
if (!w || !h) return EINA_FALSE;
|
|
|
|
|
|
|
|
if (!ctx->gl_engine)
|
|
|
|
{
|
|
|
|
Eina_Bool async_unref;
|
|
|
|
int dw = 0, dh = 0;
|
|
|
|
|
|
|
|
// Copy the image into our input buffer. We could optimize by reusing the buffer.
|
|
|
|
|
|
|
|
void *surface = evas_filter_buffer_backing_get(ctx, bufid);
|
|
|
|
if (!surface) return EINA_FALSE;
|
|
|
|
|
|
|
|
ENFN->image_size_get(ENDT, image, &dw, &dh);
|
|
|
|
if (!dw || !dh) return EINA_FALSE;
|
|
|
|
|
|
|
|
if (w != dw || h != dh)
|
|
|
|
WRN("Target surface size differs from the image to draw");
|
|
|
|
|
|
|
|
async_unref = ENFN->image_draw(ENDT, draw_context, surface, image,
|
|
|
|
0, 0, w, h,
|
|
|
|
0, 0, dw, dh,
|
|
|
|
EINA_TRUE, do_async);
|
|
|
|
if (do_async && async_unref)
|
|
|
|
{
|
|
|
|
#ifdef EVAS_CSERVE2
|
|
|
|
if (evas_cserve2_use_get())
|
|
|
|
evas_cache2_image_ref((Image_Entry *)image);
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
evas_cache_image_ref((Image_Entry *)image);
|
|
|
|
|
|
|
|
evas_unref_queue_image_put(ctx->evas, image);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Evas_Filter_Buffer *fb;
|
|
|
|
|
|
|
|
fb = _filter_buffer_get(ctx, bufid);
|
|
|
|
_filter_buffer_backing_free(fb);
|
|
|
|
fb->glimage = image;
|
|
|
|
fb->allocated_gl = EINA_FALSE;
|
|
|
|
_filter_buffer_glimage_pixels_read(fb);
|
|
|
|
fb->glimage = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return EINA_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-12-08 22:57:50 -08:00
|
|
|
/* Clip full input rect (0, 0, sw, sh) to target (dx, dy, dw, dh)
|
|
|
|
* and get source's clipped sx, sy as well as destination x, y, cols and rows */
|
|
|
|
void
|
|
|
|
_clip_to_target(int *sx /* OUT */, int *sy /* OUT */, int sw, int sh,
|
|
|
|
int ox, int oy, int dw, int dh,
|
|
|
|
int *dx /* OUT */, int *dy /* OUT */,
|
|
|
|
int *rows /* OUT */, int *cols /* OUT */)
|
|
|
|
{
|
|
|
|
if (ox > 0)
|
|
|
|
{
|
2014-03-03 00:45:15 -08:00
|
|
|
(*sx) = 0;
|
2013-12-08 22:57:50 -08:00
|
|
|
(*dx) = ox;
|
2014-01-22 01:41:00 -08:00
|
|
|
(*cols) = sw;
|
|
|
|
if (((*dx) + (*cols)) > (dw))
|
2013-12-08 22:57:50 -08:00
|
|
|
(*cols) = dw - (*dx);
|
|
|
|
}
|
|
|
|
else if (ox < 0)
|
|
|
|
{
|
2014-03-03 00:45:15 -08:00
|
|
|
(*dx) = 0;
|
2013-12-08 22:57:50 -08:00
|
|
|
(*sx) = (-ox);
|
|
|
|
(*cols) = sw - (*sx);
|
|
|
|
if ((*cols) > dw) (*cols) = dw;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-03-03 18:44:19 -08:00
|
|
|
(*sx) = 0;
|
2014-03-03 00:45:15 -08:00
|
|
|
(*dx) = 0;
|
2013-12-08 22:57:50 -08:00
|
|
|
(*cols) = sw;
|
|
|
|
if ((*cols) > dw) (*cols) = dw;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (oy > 0)
|
|
|
|
{
|
2014-03-03 00:45:15 -08:00
|
|
|
(*sy) = 0;
|
2013-12-08 22:57:50 -08:00
|
|
|
(*dy) = oy;
|
2014-01-22 01:41:00 -08:00
|
|
|
(*rows) = sh;
|
|
|
|
if (((*dy) + (*rows)) > (dh))
|
2013-12-08 22:57:50 -08:00
|
|
|
(*rows) = dh - (*dy);
|
|
|
|
}
|
|
|
|
else if (oy < 0)
|
|
|
|
{
|
2014-03-03 00:45:15 -08:00
|
|
|
(*dy) = 0;
|
2013-12-08 22:57:50 -08:00
|
|
|
(*sy) = (-oy);
|
|
|
|
(*rows) = sh - (*sy);
|
|
|
|
if ((*rows) > dh) (*rows) = dh;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-03-03 18:44:19 -08:00
|
|
|
(*sy) = 0;
|
2014-03-03 00:45:15 -08:00
|
|
|
(*dy) = 0;
|
2013-12-08 22:57:50 -08:00
|
|
|
(*rows) = sh;
|
|
|
|
if ((*rows) > dh) (*rows) = dh;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static const char *
|
|
|
|
_filter_name_get(int mode)
|
|
|
|
{
|
|
|
|
#define FNAME(a) case EVAS_FILTER_MODE_ ## a: return "EVAS_FILTER_MODE_" #a
|
|
|
|
switch (mode)
|
|
|
|
{
|
|
|
|
FNAME(BLEND);
|
|
|
|
FNAME(BLUR);
|
|
|
|
FNAME(CURVE);
|
|
|
|
FNAME(DISPLACE);
|
|
|
|
FNAME(MASK);
|
|
|
|
FNAME(BUMP);
|
2013-12-12 17:03:47 -08:00
|
|
|
FNAME(FILL);
|
2013-12-08 22:57:50 -08:00
|
|
|
default: return "INVALID";
|
|
|
|
}
|
|
|
|
#undef FNAME
|
|
|
|
}
|
|
|
|
|
|
|
|
static Eina_Bool
|
|
|
|
_filter_command_run(Evas_Filter_Command *cmd)
|
|
|
|
{
|
|
|
|
Evas_Filter_Apply_Func func = NULL;
|
|
|
|
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(cmd->output, EINA_FALSE);
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(cmd->input, EINA_FALSE);
|
|
|
|
|
2014-03-06 17:59:54 -08:00
|
|
|
DBG("Command %d (%s): %d [%d] --> %d",
|
2013-12-08 22:57:50 -08:00
|
|
|
cmd->id, _filter_name_get(cmd->mode),
|
|
|
|
cmd->input->id, cmd->mask ? cmd->mask->id : 0, cmd->output->id);
|
|
|
|
|
2014-01-02 01:44:01 -08:00
|
|
|
if (!cmd->input->w && !cmd->input->h
|
|
|
|
&& (cmd->mode != EVAS_FILTER_MODE_FILL))
|
2013-12-08 22:57:50 -08:00
|
|
|
{
|
|
|
|
DBG("Skipping processing of empty input buffer (size 0x0)");
|
|
|
|
return EINA_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((cmd->output->w <= 0) || (cmd->output->h <= 0))
|
|
|
|
{
|
|
|
|
ERR("Output size invalid: %dx%d", cmd->output->w, cmd->output->h);
|
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
//func = cmd->ENFN->filter_command_func_get(cmd);
|
|
|
|
// FIXME: Must call engine function, not CPU directly.
|
|
|
|
|
|
|
|
switch (cmd->mode)
|
|
|
|
{
|
|
|
|
case EVAS_FILTER_MODE_BLEND:
|
|
|
|
func = evas_filter_blend_cpu_func_get(cmd);
|
|
|
|
break;
|
|
|
|
case EVAS_FILTER_MODE_BLUR:
|
|
|
|
func = evas_filter_blur_cpu_func_get(cmd);
|
|
|
|
break;
|
|
|
|
case EVAS_FILTER_MODE_CURVE:
|
|
|
|
func = evas_filter_curve_cpu_func_get(cmd);
|
|
|
|
break;
|
|
|
|
case EVAS_FILTER_MODE_DISPLACE:
|
|
|
|
func = evas_filter_displace_cpu_func_get(cmd);
|
|
|
|
break;
|
2013-12-12 00:46:46 -08:00
|
|
|
case EVAS_FILTER_MODE_FILL:
|
|
|
|
func = evas_filter_fill_cpu_func_get(cmd);
|
|
|
|
break;
|
2013-12-08 22:57:50 -08:00
|
|
|
case EVAS_FILTER_MODE_MASK:
|
|
|
|
func = evas_filter_mask_cpu_func_get(cmd);
|
|
|
|
break;
|
|
|
|
case EVAS_FILTER_MODE_BUMP:
|
|
|
|
func = evas_filter_bump_map_cpu_func_get(cmd);
|
|
|
|
break;
|
2014-01-06 23:44:10 -08:00
|
|
|
case EVAS_FILTER_MODE_TRANSFORM:
|
|
|
|
func = evas_filter_transform_cpu_func_get(cmd);
|
|
|
|
break;
|
2013-12-08 22:57:50 -08:00
|
|
|
default:
|
2013-12-29 22:43:52 -08:00
|
|
|
CRI("Invalid filter mode.");
|
2013-12-08 22:57:50 -08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// END OF FIXME
|
|
|
|
|
|
|
|
if (!func)
|
|
|
|
{
|
2013-12-29 22:43:52 -08:00
|
|
|
CRI("No function to process this filter!");
|
2013-12-08 22:57:50 -08:00
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
|
|
|
|
2014-01-22 23:54:50 -08:00
|
|
|
return func(cmd);
|
2013-12-08 22:57:50 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
static Eina_Bool
|
|
|
|
_filter_chain_run(Evas_Filter_Context *ctx)
|
|
|
|
{
|
|
|
|
Evas_Filter_Command *cmd;
|
2014-03-02 23:58:18 -08:00
|
|
|
Eina_Bool ok = EINA_FALSE;
|
2014-03-11 22:06:23 -07:00
|
|
|
void *buffer;
|
2013-12-08 22:57:50 -08:00
|
|
|
|
2014-03-10 22:50:11 -07:00
|
|
|
DEBUG_TIME_BEGIN();
|
|
|
|
|
2014-02-06 18:22:36 -08:00
|
|
|
ctx->running = EINA_TRUE;
|
2013-12-08 22:57:50 -08:00
|
|
|
EINA_INLIST_FOREACH(ctx->commands, cmd)
|
|
|
|
{
|
|
|
|
ok = _filter_command_run(cmd);
|
|
|
|
if (!ok)
|
|
|
|
{
|
|
|
|
ERR("Filter processing failed!");
|
2014-02-06 18:22:36 -08:00
|
|
|
goto end;
|
2013-12-08 22:57:50 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-02-06 18:22:36 -08:00
|
|
|
ok = _filter_target_render(ctx);
|
2014-01-16 22:05:23 -08:00
|
|
|
|
2014-02-06 18:22:36 -08:00
|
|
|
end:
|
|
|
|
ctx->running = EINA_FALSE;
|
2014-03-10 22:50:11 -07:00
|
|
|
DEBUG_TIME_END();
|
2014-03-11 22:06:23 -07:00
|
|
|
|
|
|
|
EINA_LIST_FREE(ctx->post_run.buffers_to_free, buffer)
|
|
|
|
{
|
|
|
|
if (ctx->gl_engine)
|
|
|
|
ENFN->image_free(ENDT, buffer);
|
|
|
|
}
|
|
|
|
|
2014-02-06 18:22:36 -08:00
|
|
|
return ok;
|
2013-12-08 22:57:50 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
_filter_thread_run_cb(void *data)
|
|
|
|
{
|
|
|
|
Evas_Filter_Context *ctx = data;
|
2014-03-03 22:17:11 -08:00
|
|
|
Eina_Bool success;
|
2014-03-02 02:08:22 -08:00
|
|
|
|
2014-03-03 22:17:11 -08:00
|
|
|
success = _filter_chain_run(ctx);
|
2014-03-02 02:08:22 -08:00
|
|
|
|
2013-12-08 22:57:50 -08:00
|
|
|
if (ctx->post_run.cb)
|
2014-03-03 22:17:11 -08:00
|
|
|
ctx->post_run.cb(ctx, ctx->post_run.data, success);
|
2013-12-08 22:57:50 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
Eina_Bool
|
2014-01-22 23:54:50 -08:00
|
|
|
evas_filter_run(Evas_Filter_Context *ctx)
|
2013-12-08 22:57:50 -08:00
|
|
|
{
|
|
|
|
Eina_Bool ret;
|
|
|
|
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, EINA_FALSE);
|
|
|
|
|
|
|
|
if (!ctx->commands)
|
|
|
|
return EINA_TRUE;
|
|
|
|
|
2014-01-16 22:05:23 -08:00
|
|
|
if (ctx->gl_engine)
|
2014-03-06 17:59:54 -08:00
|
|
|
INF("EXPERIMENTAL OpenGL support! The text filters will be very slow!");
|
2014-01-16 22:05:23 -08:00
|
|
|
|
2014-01-22 23:54:50 -08:00
|
|
|
if (ctx->async)
|
2013-12-08 22:57:50 -08:00
|
|
|
{
|
|
|
|
evas_thread_cmd_enqueue(_filter_thread_run_cb, ctx);
|
|
|
|
return EINA_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = _filter_chain_run(ctx);
|
2014-03-11 22:06:23 -07:00
|
|
|
|
2013-12-08 22:57:50 -08:00
|
|
|
if (ctx->post_run.cb)
|
2014-03-03 22:17:11 -08:00
|
|
|
ctx->post_run.cb(ctx, ctx->post_run.data, ret);
|
2013-12-08 22:57:50 -08:00
|
|
|
return ret;
|
|
|
|
}
|