Evas filters: Add internal function _program_run

This will allow changing the state of the filter and re-run it
without re-creating the Lua_State object. This is to handle size,
color, animation state and scale changes (amongst other things).
This commit is contained in:
Jean-Philippe Andre 2015-05-18 17:35:49 +09:00
parent 6db0ff4229
commit 2faaef966e
5 changed files with 86 additions and 20 deletions

View File

@ -3315,7 +3315,7 @@ start_draw:
if (!ok) goto state_write;
evas_filter_context_proxy_render_all(filter, eo_obj, EINA_FALSE);
ok = evas_filter_context_buffers_allocate_all(filter, W, H);
ok = evas_filter_context_buffers_allocate_all(filter);
if (!ok) goto state_write;
if (ENFN->gl_surface_read_pixels)

View File

@ -1760,7 +1760,6 @@ evas_object_text_render(Evas_Object *eo_obj,
* image to GL.
*/
W = obj->cur->geometry.w;
H = obj->cur->geometry.h;
X = obj->cur->geometry.x;
@ -1837,6 +1836,7 @@ evas_object_text_render(Evas_Object *eo_obj,
}
filter = evas_filter_context_new(obj->layer->evas, do_async);
evas_filter_program_run(fcow->chain);
ok = evas_filter_context_program_use(filter, fcow->chain);
if (!filter || !ok)
{
@ -1856,7 +1856,7 @@ evas_object_text_render(Evas_Object *eo_obj,
ENFN->context_color_set(ENDT, filter_ctx, 255, 255, 255, 255);
// Allocate all buffers now
evas_filter_context_buffers_allocate_all(filter, W, H);
evas_filter_context_buffers_allocate_all(filter);
evas_filter_target_set(filter, context, surface, X + x, Y + y);
// Steal output and release previous
@ -2379,7 +2379,6 @@ EOLIAN static void
_evas_text_filter_program_set(Eo *eo_obj, Evas_Text_Data *o, const char *arg)
{
Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
Evas_Filter_Program *pgm = NULL;
if (!o) return;
@ -2393,8 +2392,9 @@ _evas_text_filter_program_set(Eo *eo_obj, Evas_Text_Data *o, const char *arg)
evas_filter_program_del(fcow->chain);
if (arg)
{
pgm = evas_filter_program_new("Evas_Text: Filter Program", EINA_TRUE);
pgm = evas_filter_program_new("Evas_Text", EINA_TRUE);
evas_filter_program_source_set_all(pgm, fcow->sources);
evas_filter_program_state_set(pgm, obj->cur->geometry.w, obj->cur->geometry.h);
if (!evas_filter_program_parse(pgm, arg))
{
ERR("Parsing failed!");

View File

@ -22,6 +22,8 @@
# include "evas_cs2_private.h"
#endif
#define _assert(a) if (!(a)) CRI("Failed on %s", #a);
static void _buffer_free(Evas_Filter_Buffer *fb);
static void _command_del(Evas_Filter_Context *ctx, Evas_Filter_Command *cmd);
static RGBA_Image *_rgba_image_alloc(Evas_Filter_Buffer const *fb, void *data);
@ -205,13 +207,13 @@ evas_filter_context_proxy_render_all(Evas_Filter_Context *ctx, Eo *eo_obj,
{
// TODO: Lock current object as proxyrendering (see image obj)
source = eo_data_scope_get(fb->source, EVAS_OBJECT_CLASS);
_assert(fb->w == source->cur->geometry.w);
_assert(fb->h == source->cur->geometry.h);
if (source->proxy->surface && !source->proxy->redraw)
{
DBG("Source already rendered: '%s' of type '%s'",
fb->source_name, eo_class_name_get(eo_class_get(fb->source)));
_filter_buffer_backing_free(fb);
fb->w = source->cur->geometry.w;
fb->h = source->cur->geometry.h;
if (!ctx->gl_engine)
{
fb->backing = source->proxy->surface;
@ -232,8 +234,6 @@ evas_filter_context_proxy_render_all(Evas_Filter_Context *ctx, Eo *eo_obj,
source->proxy->redraw ? "redraw" : "no surface");
evas_render_proxy_subrender(ctx->evas->evas, fb->source, eo_obj, obj, do_async);
_filter_buffer_backing_free(fb);
fb->w = source->cur->geometry.w;
fb->h = source->cur->geometry.h;
if (!ctx->gl_engine)
{
fb->backing = source->proxy->surface;
@ -355,16 +355,16 @@ _rgba_image_alloc(Evas_Filter_Buffer const *fb, void *data)
}
Eina_Bool
evas_filter_context_buffers_allocate_all(Evas_Filter_Context *ctx,
unsigned w, unsigned h)
evas_filter_context_buffers_allocate_all(Evas_Filter_Context *ctx)
{
Evas_Filter_Command *cmd;
Evas_Filter_Buffer *fb;
Eina_List *li;
unsigned w, h;
EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, EINA_FALSE);
ctx->w = w;
ctx->h = h;
w = ctx->w;
h = ctx->w;
//DBG("Allocating all buffers based on output size %ux%u", w, h);

View File

@ -282,6 +282,7 @@ typedef struct _Buffer
struct {
int l, r, t, b; // Used for padding calculation. Can change over time.
} pad;
int w, h;
Eina_Bool alpha : 1;
} Buffer;
@ -320,9 +321,12 @@ struct _Evas_Filter_Program
struct {
int l, r, t, b;
} pad;
int w, h;
lua_State *L;
Eina_Bool valid : 1;
Eina_Bool padding_calc : 1; // Padding has been calculated
Eina_Bool padding_set : 1; // Padding has been forced
Eina_Bool changed : 1; // State (w,h) changed, needs re-run of Lua
};
/* Instructions */
@ -1568,6 +1572,9 @@ evas_filter_program_del(Evas_Filter_Program *pgm)
if (!pgm) return;
if (pgm->L)
lua_close(pgm->L);
EINA_INLIST_FREE(pgm->buffers, buf)
{
pgm->buffers = eina_inlist_remove(pgm->buffers, EINA_INLIST_GET(buf));
@ -1679,7 +1686,7 @@ fail:
}
static Instruction_Param *
_paramameter_get_by_id(Evas_Filter_Instruction *instr, int id)
_parameter_get_by_id(Evas_Filter_Instruction *instr, int id)
{
Instruction_Param *param;
int i = 0;
@ -1734,7 +1741,7 @@ _lua_instruction_run(lua_State *L, Evas_Filter_Instruction *instr)
else if (lua_isnumber(L, -2))
{
int idx = (int) lua_tonumber(L, -2);
param = _paramameter_get_by_id(instr, idx - 1);
param = _parameter_get_by_id(instr, idx - 1);
if (!param)
{
ERR("Too many parameters for the function %s", instr->name);
@ -2092,20 +2099,48 @@ evas_filter_program_parse(Evas_Filter_Program *pgm, const char *str)
if (ok)
ok = !lua_pcall(L, 0, LUA_MULTRET, 0);
else
if (!ok || !pgm->instructions)
{
const char *msg = lua_tostring(L, -1);
ERR("Lua parsing failed: %s", msg);
lua_close(L);
}
lua_close(L);
ok &= (pgm->instructions != NULL);
else
pgm->L = L;
pgm->valid = ok;
pgm->padding_calc = EINA_FALSE;
return ok;
}
/** Run a program, must be already loaded */
EAPI Eina_Bool
evas_filter_program_run(Evas_Filter_Program *pgm)
{
Eina_Bool ok;
EINA_SAFETY_ON_NULL_RETURN_VAL(pgm, EINA_FALSE);
if (!pgm->L)
{
ERR("Lua state is not set. Something is wrong.");
return EINA_FALSE;
}
if (!pgm->changed)
return EINA_TRUE;
ok = !lua_pcall(pgm->L, 0, LUA_MULTRET, 0);
if (!ok)
{
const char *msg = lua_tostring(pgm->L, -1);
ERR("Lua execution failed: %s", msg);
}
return ok;
}
/** Evaluate required padding to correctly apply an effect */
EAPI Eina_Bool
@ -2180,6 +2215,21 @@ evas_filter_program_new(const char *name, Eina_Bool input_alpha)
return pgm;
}
EAPI void
evas_filter_program_state_set(Evas_Filter_Program *pgm, int w, int h)
{
Eina_Bool changed = EINA_FALSE;
#define SET(a) do { if (pgm->a != a) { changed = 1; pgm->a = a; } } while (0)
EINA_SAFETY_ON_NULL_RETURN(pgm);
SET(w);
SET(h);
pgm->changed |= changed;
#undef SET
}
/** Bind objects for proxy rendering */
EAPI void
evas_filter_program_source_set_all(Evas_Filter_Program *pgm,
@ -2739,6 +2789,10 @@ evas_filter_context_program_use(Evas_Filter_Context *ctx,
DBG("Using program '%s' for context %p", pgm->name, ctx);
// Copy current state (size, edje state val, color class, etc...)
ctx->w = pgm->w;
ctx->h = pgm->h;
// Create empty context with all required buffers
evas_filter_context_clear(ctx);
EINA_INLIST_FOREACH(pgm->buffers, buf)
@ -2746,6 +2800,7 @@ evas_filter_context_program_use(Evas_Filter_Context *ctx,
buf->cid = evas_filter_buffer_empty_new(ctx, buf->alpha);
if (buf->proxy)
{
Evas_Object_Protected_Data *source;
Evas_Filter_Proxy_Binding *pb;
Evas_Filter_Buffer *fb;
@ -2757,6 +2812,15 @@ evas_filter_context_program_use(Evas_Filter_Context *ctx,
fb->source = pb->eo_source;
fb->source_name = eina_stringshare_ref(pb->name);
fb->ctx->has_proxies = EINA_TRUE;
source = eo_data_scope_get(fb->source, EVAS_OBJECT_CLASS);
fb->w = source->cur->geometry.w;
fb->h = source->cur->geometry.h;
}
else
{
buf->w = ctx->w;
buf->h = ctx->h;
}
}

View File

@ -118,6 +118,8 @@ enum _Evas_Filter_Transform_Flags
/* Parser stuff (high level API) */
EAPI Evas_Filter_Program *evas_filter_program_new(const char *name, Eina_Bool input_alpha);
EAPI Eina_Bool evas_filter_program_run(Evas_Filter_Program *pgm);
EAPI void evas_filter_program_state_set(Evas_Filter_Program *pgm, int w, int h);
EAPI Eina_Bool evas_filter_program_parse(Evas_Filter_Program *pgm, const char *str);
EAPI void evas_filter_program_del(Evas_Filter_Program *pgm);
Eina_Bool evas_filter_context_program_use(Evas_Filter_Context *ctx, Evas_Filter_Program *pgm);
@ -130,7 +132,7 @@ Evas_Filter_Context *evas_filter_context_new(Evas_Public_Data *evas, Eina_Bo
void evas_filter_context_destroy(Evas_Filter_Context *ctx);
void evas_filter_context_post_run_callback_set(Evas_Filter_Context *ctx, Evas_Filter_Cb cb, void *data);
#define evas_filter_context_autodestroy(ctx) evas_filter_context_post_run_callback_set(ctx, ((Evas_Filter_Cb) evas_filter_context_destroy), ctx)
Eina_Bool evas_filter_context_buffers_allocate_all(Evas_Filter_Context *ctx, unsigned w, unsigned h);
Eina_Bool evas_filter_context_buffers_allocate_all(Evas_Filter_Context *ctx);
int evas_filter_buffer_empty_new(Evas_Filter_Context *ctx, Eina_Bool alpha_only);
int evas_filter_buffer_image_new(Evas_Filter_Context *ctx, void *image);