From 2faaef966e41b35656fd77be94701009ad183c42 Mon Sep 17 00:00:00 2001 From: Jean-Philippe Andre Date: Mon, 18 May 2015 17:35:49 +0900 Subject: [PATCH] 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). --- src/lib/evas/canvas/evas_object_image.c | 2 +- src/lib/evas/canvas/evas_object_text.c | 8 +-- src/lib/evas/filters/evas_filter.c | 16 ++--- src/lib/evas/filters/evas_filter_parser.c | 76 +++++++++++++++++++++-- src/lib/evas/include/evas_filter.h | 4 +- 5 files changed, 86 insertions(+), 20 deletions(-) diff --git a/src/lib/evas/canvas/evas_object_image.c b/src/lib/evas/canvas/evas_object_image.c index b2f8b95fb2..a272206bc6 100644 --- a/src/lib/evas/canvas/evas_object_image.c +++ b/src/lib/evas/canvas/evas_object_image.c @@ -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) diff --git a/src/lib/evas/canvas/evas_object_text.c b/src/lib/evas/canvas/evas_object_text.c index d7ee55e049..42620cb347 100644 --- a/src/lib/evas/canvas/evas_object_text.c +++ b/src/lib/evas/canvas/evas_object_text.c @@ -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!"); diff --git a/src/lib/evas/filters/evas_filter.c b/src/lib/evas/filters/evas_filter.c index 0f248705fd..523018f0be 100644 --- a/src/lib/evas/filters/evas_filter.c +++ b/src/lib/evas/filters/evas_filter.c @@ -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); diff --git a/src/lib/evas/filters/evas_filter_parser.c b/src/lib/evas/filters/evas_filter_parser.c index 692afc9137..1f9f9d3a12 100644 --- a/src/lib/evas/filters/evas_filter_parser.c +++ b/src/lib/evas/filters/evas_filter_parser.c @@ -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; } } diff --git a/src/lib/evas/include/evas_filter.h b/src/lib/evas/include/evas_filter.h index 22804413c5..b8b23616ad 100644 --- a/src/lib/evas/include/evas_filter.h +++ b/src/lib/evas/include/evas_filter.h @@ -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);