jpeg pushed a commit to branch master. http://git.enlightenment.org/core/efl.git/commit/?id=1bf24f87626b438598936ad4f780f7877447f496
commit 1bf24f87626b438598936ad4f780f7877447f496 Author: Jean-Philippe Andre <[email protected]> Date: Wed Mar 22 16:55:26 2017 +0900 evas filters: Refactor to support reuse of buffers This will reuse existing buffers by resetting only the minimum required in the filter context (also reused). Work in progress, as the actual reuse is disabled for now. --- src/bin/elementary/test_evas_snapshot.c | 1 - src/lib/evas/canvas/evas_filter_mixin.c | 109 ++++++++++++++---- src/lib/evas/canvas/evas_object_main.c | 2 +- src/lib/evas/canvas/evas_object_textblock.c | 4 +- src/lib/evas/filters/evas_filter.c | 171 ++++++++++++++++++++++++---- src/lib/evas/filters/evas_filter_parser.c | 73 ++++++------ src/lib/evas/filters/evas_filter_private.h | 8 +- src/lib/evas/include/evas_filter.h | 10 +- src/lib/evas/include/evas_private.h | 3 + 9 files changed, 286 insertions(+), 95 deletions(-) diff --git a/src/bin/elementary/test_evas_snapshot.c b/src/bin/elementary/test_evas_snapshot.c index 94d6e16..13e0458 100644 --- a/src/bin/elementary/test_evas_snapshot.c +++ b/src/bin/elementary/test_evas_snapshot.c @@ -111,7 +111,6 @@ test_evas_snapshot(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *e efl_pack_grid(grid, efl_added, 1, 1, GRID_SIZE - 2, GRID_SIZE - 2), efl_gfx_visible_set(efl_added, 1)); - // Objects above snapshot // 1. Opaque rect, not changing o = evas_object_rectangle_add(win); diff --git a/src/lib/evas/canvas/evas_filter_mixin.c b/src/lib/evas/canvas/evas_filter_mixin.c index 45db424..fab03ba 100644 --- a/src/lib/evas/canvas/evas_filter_mixin.c +++ b/src/lib/evas/canvas/evas_filter_mixin.c @@ -43,6 +43,8 @@ _filter_end_sync(Evas_Filter_Context *ctx, Evas_Object_Protected_Data *obj, Evas_Filter_Data *pd, Eina_Bool success) { void *previous = pd->data->output; + Eina_Bool destroy = !pd->data->reuse; + Evas_Object_Filter_Data *fcow; Eo *eo_obj = obj->object; if (!success) @@ -50,10 +52,10 @@ _filter_end_sync(Evas_Filter_Context *ctx, Evas_Object_Protected_Data *obj, ERR("Filter failed at runtime!"); evas_filter_invalid_set(eo_obj, EINA_TRUE); evas_filter_dirty(eo_obj); + destroy = EINA_TRUE; } else { - Evas_Object_Filter_Data *fcow; void *output = evas_filter_buffer_backing_get(ctx, EVAS_FILTER_BUFFER_OUTPUT_ID, EINA_FALSE); fcow = FCOW_BEGIN(pd); @@ -61,9 +63,29 @@ _filter_end_sync(Evas_Filter_Context *ctx, Evas_Object_Protected_Data *obj, FCOW_END(fcow, pd); } - // Destroy context as we won't reuse it. - evas_filter_buffer_backing_release(ctx, previous); - evas_filter_context_destroy(ctx); + if (EINA_UNLIKELY(ctx != pd->data->context)) + { + ERR("Filter context has changed! Destroying it now..."); + fcow = FCOW_BEGIN(pd); + evas_filter_context_destroy(fcow->context); + fcow->context = NULL; + FCOW_END(fcow, pd); + destroy = EINA_TRUE; + } + + if (destroy) + { + evas_filter_buffer_backing_release(ctx, previous); + evas_filter_context_destroy(ctx); + ctx = NULL; + } + + if (pd->data->context != ctx) + { + fcow = FCOW_BEGIN(pd); + fcow->context = ctx; + FCOW_END(fcow, pd); + } } static void @@ -192,13 +214,6 @@ evas_filter_object_render(Eo *eo_obj, Evas_Object_Protected_Data *obj, Evas_Object_Filter_Data *fcow; Evas_Filter_Padding pad; - /* NOTE: Filter rendering is now done ENTIRELY on CPU. - * So we rely on cache/cache2 to allocate a real image buffer, - * that we can draw to. The OpenGL texture will be created only - * after the rendering has been done, as we simply push the output - * image to GL. - */ - W = obj->cur->geometry.w; H = obj->cur->geometry.h; X = obj->cur->geometry.x; @@ -217,7 +232,7 @@ evas_filter_object_render(Eo *eo_obj, Evas_Object_Protected_Data *obj, obj->cur->clipper->cur->cache.clip.b, obj->cur->clipper->cur->cache.clip.a); else - ENFN->context_multiplier_unset(output, context); + ENFN->context_multiplier_unset(output, context); if (!pd->data->chain) { @@ -295,22 +310,57 @@ evas_filter_object_render(Eo *eo_obj, Evas_Object_Protected_Data *obj, _evas_filter_state_set_internal(pd->data->chain, pd); } - filter = evas_filter_context_new(obj->layer->evas, do_async, 0); - - // Run script - ok = evas_filter_context_program_use(filter, pd->data->chain); - if (!filter || !ok) + filter = pd->data->context; + if (filter) { - ERR("Parsing failed?"); - evas_filter_context_destroy(filter); + int prev_w, prev_h; + Eina_Bool was_async; - if (!pd->data->invalid) + was_async = evas_filter_context_async_get(filter); + evas_filter_context_size_get(filter, &prev_w, &prev_h); + if ((!pd->data->reuse) || (was_async != do_async) || + (prev_w != W) || (prev_h != H)) { fcow = FCOW_BEGIN(pd); - fcow->invalid = EINA_TRUE; + fcow->context = NULL; FCOW_END(fcow, pd); + evas_filter_context_destroy(filter); + filter = NULL; + } + } + + if (filter) + { + ok = evas_filter_context_program_reuse(filter, pd->data->chain); + if (!ok) + { + fcow = FCOW_BEGIN(pd); + fcow->context = NULL; + FCOW_END(fcow, pd); + evas_filter_context_destroy(filter); + filter = NULL; + } + } + + if (!filter) + { + filter = evas_filter_context_new(obj->layer->evas, do_async, 0); + + // Run script + ok = evas_filter_context_program_use(filter, pd->data->chain, EINA_FALSE); + if (!filter || !ok) + { + ERR("Parsing failed?"); + evas_filter_context_destroy(filter); + + if (!pd->data->invalid) + { + fcow = FCOW_BEGIN(pd); + fcow->invalid = EINA_TRUE; + FCOW_END(fcow, pd); + } + return EINA_FALSE; } - return EINA_FALSE; } // Proxies @@ -336,15 +386,17 @@ evas_filter_object_render(Eo *eo_obj, Evas_Object_Protected_Data *obj, // Add post-run callback and run filter evas_filter_context_post_run_callback_set(filter, _filter_cb, pd); - ok = evas_filter_run(filter); fcow = FCOW_BEGIN(pd); + fcow->context = filter; fcow->changed = EINA_FALSE; fcow->async = do_async; fcow->prev_obscured = fcow->obscured; - fcow->invalid = !ok; + fcow->invalid = EINA_FALSE; FCOW_END(fcow, pd); + ok = evas_filter_context_run(filter); + if (ok) { DBG("Effect rendering done."); @@ -352,6 +404,9 @@ evas_filter_object_render(Eo *eo_obj, Evas_Object_Protected_Data *obj, } else { + fcow = FCOW_BEGIN(pd); + fcow->invalid = EINA_TRUE; + FCOW_END(fcow, pd); ERR("Rendering failed."); return EINA_FALSE; } @@ -377,6 +432,9 @@ _efl_canvas_filter_internal_efl_gfx_filter_filter_program_set(Eo *eo_obj, Evas_F { fcow->obj = obj; + if (fcow->context) + evas_filter_context_destroy(fcow->context); + // Parse filter program evas_filter_program_del(fcow->chain); eina_stringshare_replace(&fcow->name, name); @@ -613,6 +671,9 @@ _efl_canvas_filter_internal_efl_object_destructor(Eo *eo_obj, Evas_Filter_Data * obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS); e = obj->layer->evas; + if (pd->data->context) + evas_filter_context_destroy(pd->data->context); + if (pd->data->output) { if (!pd->data->async) diff --git a/src/lib/evas/canvas/evas_object_main.c b/src/lib/evas/canvas/evas_object_main.c index cab4bd1..b62ffe6 100644 --- a/src/lib/evas/canvas/evas_object_main.c +++ b/src/lib/evas/canvas/evas_object_main.c @@ -33,7 +33,7 @@ static const Evas_Object_Protected_State default_state = { 1.0, 0, EVAS_RENDER_BLEND, EINA_FALSE, EINA_FALSE, EINA_FALSE, EINA_FALSE, EINA_FALSE }; static const Evas_Object_Filter_Data default_filter = { - NULL, NULL, NULL, NULL, NULL, NULL, {}, {}, NULL, {}, EINA_FALSE, EINA_FALSE, EINA_TRUE + NULL, NULL, NULL, NULL, NULL, NULL, NULL, {}, {}, NULL, {}, EINA_FALSE, EINA_FALSE, EINA_TRUE, EINA_TRUE }; const void * const evas_object_filter_cow_default = &default_filter; static const Evas_Object_Mask_Data default_mask = { diff --git a/src/lib/evas/canvas/evas_object_textblock.c b/src/lib/evas/canvas/evas_object_textblock.c index 05166b9..8032abf 100644 --- a/src/lib/evas/canvas/evas_object_textblock.c +++ b/src/lib/evas/canvas/evas_object_textblock.c @@ -13476,7 +13476,7 @@ evas_object_textblock_render(Evas_Object *eo_obj EINA_UNUSED, ctx = evas_filter_context_new(obj->layer->evas, do_async, ti->gfx_filter); evas_filter_state_prepare(eo_obj, &state, ti); evas_filter_program_state_set(pgm, &state); - ok = evas_filter_context_program_use(ctx, pgm); + ok = evas_filter_context_program_use(ctx, pgm, EINA_FALSE); if (!ok) { evas_filter_context_destroy(ctx); @@ -13790,7 +13790,7 @@ evas_object_textblock_render(Evas_Object *eo_obj EINA_UNUSED, else if (ctx) { evas_filter_context_post_run_callback_set(ctx, _filter_cb, obj->layer->evas); - evas_filter_run(ctx); + evas_filter_context_run(ctx); } } } diff --git a/src/lib/evas/filters/evas_filter.c b/src/lib/evas/filters/evas_filter.c index 3b4c7ff..c0990a0 100644 --- a/src/lib/evas/filters/evas_filter.c +++ b/src/lib/evas/filters/evas_filter.c @@ -30,6 +30,7 @@ static void _buffer_free(Evas_Filter_Buffer *fb); static void _command_del(Evas_Filter_Context *ctx, Evas_Filter_Command *cmd); static Evas_Filter_Buffer *_buffer_alloc_new(Evas_Filter_Context *ctx, int w, int h, Eina_Bool alpha_only, Eina_Bool render, Eina_Bool draw); +static void _filter_buffer_unlock_all(Evas_Filter_Context *ctx); #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) #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) @@ -72,24 +73,37 @@ evas_filter_context_async_get(Evas_Filter_Context *ctx) return ctx->async; } +void +evas_filter_context_size_get(Evas_Filter_Context *ctx, int *w, int *h) +{ + if (w) *w = ctx->w; + if (h) *h = ctx->h; +} + /* Private function to reset the filter context. Used from parser.c */ void -evas_filter_context_clear(Evas_Filter_Context *ctx) +evas_filter_context_clear(Evas_Filter_Context *ctx, Eina_Bool keep_buffers) { - Evas_Filter_Buffer *fb; Evas_Filter_Command *cmd; + Evas_Filter_Buffer *fb; if (!ctx) return; - EINA_LIST_FREE(ctx->buffers, fb) - _buffer_free(fb); - EINA_INLIST_FREE(ctx->commands, cmd) - _command_del(ctx, cmd); + if (ctx->target.surface) ENFN->image_free(ENDT, ctx->target.surface); + if (ctx->target.mask) ENFN->image_free(ENDT, ctx->target.mask); + ctx->target.surface = NULL; + ctx->target.mask = NULL; + + if (!keep_buffers) + { + ctx->last_buffer_id = 0; + EINA_LIST_FREE(ctx->buffers, fb) + _buffer_free(fb); + } - ctx->buffers = NULL; - ctx->commands = NULL; - ctx->last_buffer_id = 0; ctx->last_command_id = 0; + EINA_INLIST_FREE(ctx->commands, cmd) + _command_del(ctx, cmd); // Note: don't reset post_run, as it it set by the client } @@ -109,6 +123,7 @@ evas_filter_context_proxy_render_all(Evas_Filter_Context *ctx, Eo *eo_obj, { Evas_Object_Protected_Data *source; Evas_Object_Protected_Data *obj; + void *proxy_surface; Evas_Filter_Buffer *fb; Eina_List *li; @@ -122,6 +137,7 @@ evas_filter_context_proxy_render_all(Evas_Filter_Context *ctx, Eo *eo_obj, source = efl_data_scope_get(fb->source, EFL_CANVAS_OBJECT_CLASS); _assert(fb->w == source->cur->geometry.w); _assert(fb->h == source->cur->geometry.h); + proxy_surface = source->proxy->surface; if (source->proxy->surface && !source->proxy->redraw) { XDBG("Source already rendered: '%s' of type '%s'", @@ -134,33 +150,75 @@ 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, EINA_FALSE, do_async); } - _filter_buffer_backing_free(fb); + if (fb->buffer) + { + void *old_surface; + + old_surface = evas_ector_buffer_drawable_image_get(fb->buffer); + if (old_surface && (old_surface != proxy_surface)) + _filter_buffer_backing_free(fb); + } XDBG("Source #%d '%s' has dimensions %dx%d", fb->id, fb->source_name, fb->w, fb->h); - fb->buffer = ENFN->ector_buffer_wrap(ENDT, obj->layer->evas->evas, source->proxy->surface); + if (!fb->buffer) fb->buffer = ENFN->ector_buffer_wrap(ENDT, obj->layer->evas->evas, source->proxy->surface); fb->alpha_only = EINA_FALSE; } } -void -evas_filter_context_destroy(Evas_Filter_Context *ctx) +Eina_Bool +evas_filter_context_program_reuse(Evas_Filter_Context *ctx, Evas_Filter_Program *pgm) { Evas_Filter_Buffer *fb; - Evas_Filter_Command *cmd; + Eina_List *li; - if (!ctx) return; + EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(pgm, EINA_FALSE); - EINA_LIST_FREE(ctx->buffers, fb) - _buffer_free(fb); - EINA_INLIST_FREE(ctx->commands, cmd) - _command_del(ctx, cmd); + _filter_buffer_unlock_all(ctx); - if (ctx->target.mask) - ctx->evas->engine.func->image_free(ctx->evas->engine.data.output, ctx->target.mask); + EINA_LIST_FOREACH(ctx->buffers, li, fb) + { + void *dc, *surface; + + fb->used = EINA_FALSE; + fb->locked = EINA_FALSE; + + if (!fb->is_render) continue; + if (fb->source) continue; + + surface = evas_ector_buffer_render_image_get(fb->buffer); + if (!surface) continue; + + dc = ENFN->context_new(ENDT); + ENFN->context_color_set(ENDT, dc, 0, 0, 0, 0); + ENFN->context_render_op_set(ENDT, dc, EVAS_RENDER_COPY); + ENFN->rectangle_draw(ENDT, dc, surface, 0, 0, fb->w, fb->h, ctx->async); + ENFN->context_free(ENDT, dc); + fb->dirty = EINA_FALSE; + } + + return evas_filter_context_program_use(ctx, pgm, EINA_TRUE); +} + +static void +_context_destroy(void *data) +{ + Evas_Filter_Context *ctx = data; + evas_filter_context_clear(ctx, EINA_FALSE); free(ctx); } void +evas_filter_context_destroy(Evas_Filter_Context *ctx) +{ + // FIXME: This is not locked... + if (ctx->running) + evas_post_render_job_add(ctx->evas, _context_destroy, ctx); + else + _context_destroy(ctx); +} + +void evas_filter_context_post_run_callback_set(Evas_Filter_Context *ctx, Evas_Filter_Cb cb, void *data) { @@ -213,6 +271,8 @@ evas_filter_context_buffers_allocate_all(Evas_Filter_Context *ctx) Eina_List *li; unsigned w, h; + if (ctx->run_count > 0) return EINA_TRUE; + EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, EINA_FALSE); w = ctx->w; h = ctx->h; @@ -231,6 +291,7 @@ evas_filter_context_buffers_allocate_all(Evas_Filter_Context *ctx) in->h = h; } + // FIXME: No need for stretch buffers with GL! if (fillmode & EVAS_FILTER_FILL_MODE_STRETCH_XY) { unsigned sw = w, sh = h; @@ -322,15 +383,69 @@ alloc_fail: } int -evas_filter_buffer_empty_new(Evas_Filter_Context *ctx, Eina_Bool alpha_only) +evas_filter_buffer_empty_new(Evas_Filter_Context *ctx, int w, int h, Eina_Bool alpha_only) { Evas_Filter_Buffer *fb; + Eina_List *li; EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, -1); - fb = _buffer_empty_new(ctx, 0, 0, alpha_only, EINA_FALSE); + EINA_LIST_FOREACH(ctx->buffers, li, fb) + { + if ((fb->alpha_only == alpha_only) && + (fb->w == w) && (fb->h == h) && !fb->dirty && !fb->used) + { + fb->used = EINA_TRUE; + return fb->id; + } + } + + fb = _buffer_empty_new(ctx, w, h, alpha_only, EINA_FALSE); if (!fb) return -1; + fb->used = EINA_TRUE; + return fb->id; +} + +int +evas_filter_buffer_proxy_new(Evas_Filter_Context *ctx, Evas_Filter_Proxy_Binding *pb, + int *w, int *h) +{ + Evas_Object_Protected_Data *source; + Evas_Filter_Buffer *fb; + Eina_List *li; + + EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, -1); + EINA_SAFETY_ON_NULL_RETURN_VAL(pb, -1); + + source = efl_data_scope_get(pb->eo_source, EFL_CANVAS_OBJECT_CLASS); + if (!source) return -1; + + // FIXME: This is not true if the source is an evas image + *w = source->cur->geometry.w; + *h = source->cur->geometry.h; + + EINA_LIST_FOREACH(ctx->buffers, li, fb) + { + if (pb->eo_source == fb->source) + { + if (fb->used) return -1; + if (fb->alpha_only) return -1; + if (!eina_streq(pb->name, fb->source_name)) return -1; + if ((*w != fb->w) || (*h != fb->h)) return -1; + + fb->used = EINA_TRUE; + return fb->id; + } + } + + fb = _buffer_empty_new(ctx, *w, *h, EINA_FALSE, EINA_FALSE); + if (!fb) return -1; + + fb->source = efl_ref(pb->eo_source); + fb->source_name = eina_stringshare_add(pb->name); + + fb->used = EINA_TRUE; return fb->id; } @@ -351,6 +466,7 @@ _buffer_alloc_new(Evas_Filter_Context *ctx, int w, int h, Eina_Bool alpha_only, fb->w = w; fb->h = h; fb->alpha_only = alpha_only; + fb->is_render = render; fb->buffer = _ector_buffer_create(fb, render, draw); if (!fb->buffer) { @@ -367,6 +483,8 @@ static void _buffer_free(Evas_Filter_Buffer *fb) { _filter_buffer_backing_free(fb); + eina_stringshare_del(fb->source_name); + efl_unref(fb->source); free(fb); } @@ -434,6 +552,7 @@ _command_new(Evas_Filter_Context *ctx, Evas_Filter_Mode mode, if (output) { cmd->draw.output_was_dirty = output->dirty; + output->is_render = EINA_TRUE; output->dirty = EINA_TRUE; } @@ -482,6 +601,7 @@ evas_filter_temporary_buffer_get(Evas_Filter_Context *ctx, int w, int h, fb = _buffer_empty_new(ctx, w, h, alpha_only, EINA_TRUE); fb->locked = EINA_TRUE; + fb->is_render = EINA_TRUE; XDBG("Created temporary buffer %d %s", fb->id, alpha_only ? "alpha" : "rgba"); return fb; @@ -1564,7 +1684,6 @@ _filter_chain_run(Evas_Filter_Context *ctx) DEBUG_TIME_BEGIN(); - ctx->running = EINA_TRUE; EINA_INLIST_FOREACH(ctx->commands, cmd) { ok = _filter_command_run(cmd); @@ -1646,7 +1765,7 @@ _filter_obscured_region_calc(Evas_Filter_Context *ctx) } Eina_Bool -evas_filter_run(Evas_Filter_Context *ctx) +evas_filter_context_run(Evas_Filter_Context *ctx) { Eina_Bool ret; @@ -1657,12 +1776,14 @@ evas_filter_run(Evas_Filter_Context *ctx) _filter_obscured_region_calc(ctx); + ctx->running = EINA_TRUE; if (ctx->async) { evas_thread_queue_flush(_filter_thread_run_cb, ctx); return EINA_TRUE; } + ctx->run_count++; ret = _filter_chain_run(ctx); if (ctx->post_run.cb) diff --git a/src/lib/evas/filters/evas_filter_parser.c b/src/lib/evas/filters/evas_filter_parser.c index 9c14e5d..60a7ecb 100644 --- a/src/lib/evas/filters/evas_filter_parser.c +++ b/src/lib/evas/filters/evas_filter_parser.c @@ -2834,48 +2834,49 @@ evas_filter_program_parse(Evas_Filter_Program *pgm, const char *str) /** Run a program, must be already loaded */ -static void +static Eina_Bool _buffers_update(Evas_Filter_Context *ctx, Evas_Filter_Program *pgm) { - Evas_Object_Protected_Data *source; Evas_Filter_Proxy_Binding *pb; - Evas_Filter_Buffer *fb; Buffer *buf; + int w, h, id; EINA_INLIST_FOREACH(pgm->buffers, buf) { if (buf->proxy) { pb = eina_hash_find(pgm->proxies, buf->proxy); - if (!pb) continue; - - buf->cid = evas_filter_buffer_empty_new(ctx, buf->alpha); - fb = _filter_buffer_get(ctx, buf->cid); - fb->source = pb->eo_source; - fb->source_name = eina_stringshare_ref(pb->name); - fb->ctx->has_proxies = EINA_TRUE; - - source = efl_data_scope_get(fb->source, EFL_CANVAS_OBJECT_CLASS); - if ((source->cur->geometry.w != buf->w) || - (source->cur->geometry.h != buf->h)) - pgm->changed = EINA_TRUE; - buf->w = fb->w = source->cur->geometry.w; - buf->h = fb->h = source->cur->geometry.h; - XDBG("Created proxy buffer %d %s '%s'", fb->id, - buf->alpha ? "alpha" : "rgba", buf->name); + if (!pb) return EINA_FALSE; + + ctx->has_proxies = EINA_TRUE; + id = evas_filter_buffer_proxy_new(ctx, pb, &w, &h); + if (id < 0) return EINA_FALSE; + + buf->cid = id; + buf->w = w; + buf->h = h; + + XDBG("Created proxy buffer #%d %dx%d %s '%s'", buf->cid, + w, h, buf->alpha ? "alpha" : "rgba", buf->name); } else { - if ((buf->w != pgm->state.w) || (buf->h != pgm->state.h)) - pgm->changed = EINA_TRUE; - buf->cid = evas_filter_buffer_empty_new(ctx, buf->alpha); - fb = _filter_buffer_get(ctx, buf->cid); - fb->w = buf->w = pgm->state.w; - fb->h = buf->h = pgm->state.h; - XDBG("Created context buffer %d %s '%s'", fb->id, - buf->alpha ? "alpha" : "rgba", buf->name); + w = pgm->state.w; + h = pgm->state.h; + + id = evas_filter_buffer_empty_new(ctx, w, h, buf->alpha); + if (id < 0) return EINA_FALSE; + + buf->cid = id; + buf->w = w; + buf->h = h; + + XDBG("Created context buffer #%d %dx%d %s '%s'", buf->cid, + w, h, buf->alpha ? "alpha" : "rgba", buf->name); } } + + return EINA_TRUE; } /** Evaluate required padding to correctly apply an effect */ @@ -3401,11 +3402,8 @@ _command_from_instruction(Evas_Filter_Context *ctx, cmd = instr2cmd(ctx, instr, dc); if (!cmd) return EINA_FALSE; - if (cmd->output && ctx->gl) - { - if (ENFN->gfx_filter_supports(ENDT, cmd) == EVAS_FILTER_SUPPORT_GL) - cmd->output->is_render = EINA_TRUE; - } + if (cmd->output) + cmd->output->is_render = EINA_TRUE; return EINA_TRUE; } @@ -3475,7 +3473,8 @@ _instruction_dump(Evas_Filter_Instruction *instr) Eina_Bool evas_filter_context_program_use(Evas_Filter_Context *ctx, - Evas_Filter_Program *pgm) + Evas_Filter_Program *pgm, + Eina_Bool reuse) { Evas_Filter_Instruction *instr; Eina_Bool success = EINA_FALSE; @@ -3492,7 +3491,7 @@ evas_filter_context_program_use(Evas_Filter_Context *ctx, ctx->h = pgm->state.h; // Create empty context with all required buffers - evas_filter_context_clear(ctx); + evas_filter_context_clear(ctx, reuse); if (pgm->changed) { @@ -3508,7 +3507,9 @@ evas_filter_context_program_use(Evas_Filter_Context *ctx, goto end; } } - _buffers_update(ctx, pgm); + + // Create or update all buffers + if (!_buffers_update(ctx, pgm)) goto end; // Compute and save padding info evas_filter_program_padding_get(pgm, &ctx->pad.final, &ctx->pad.calculated); @@ -3528,7 +3529,7 @@ evas_filter_context_program_use(Evas_Filter_Context *ctx, pgm->changed = EINA_FALSE; end: - if (!success) evas_filter_context_clear(ctx); + if (!success) evas_filter_context_clear(ctx, EINA_FALSE); if (dc) ENFN->context_free(ENDT, dc); return success; } diff --git a/src/lib/evas/filters/evas_filter_private.h b/src/lib/evas/filters/evas_filter_private.h index c62262a..fb55aaf 100644 --- a/src/lib/evas/filters/evas_filter_private.h +++ b/src/lib/evas/filters/evas_filter_private.h @@ -157,10 +157,13 @@ struct _Evas_Filter_Context Eina_Bool color_use : 1; } target; + volatile int running; + int run_count; + Eina_Bool async : 1; - Eina_Bool running : 1; Eina_Bool has_proxies : 1; Eina_Bool gl : 1; + }; struct _Evas_Filter_Command @@ -249,6 +252,7 @@ struct _Evas_Filter_Buffer Ector_Buffer *buffer; int w, h; + Eina_Bool used : 1; // This buffer is in use (useful for reuse of context) Eina_Bool alpha_only : 1; // 1 channel (A) instead of 4 (RGBA) Eina_Bool transient : 1; // temporary buffer (automatic allocation) Eina_Bool locked : 1; // internal flag @@ -269,7 +273,7 @@ enum _Evas_Filter_Support EVAS_FILTER_SUPPORT_GL }; -void evas_filter_context_clear(Evas_Filter_Context *ctx); +void evas_filter_context_clear(Evas_Filter_Context *ctx, Eina_Bool keep_buffers); void evas_filter_context_source_set(Evas_Filter_Context *ctx, Evas_Object *eo_proxy, Evas_Object *eo_source, int bufid, Eina_Stringshare *name); /* Utility functions */ diff --git a/src/lib/evas/include/evas_filter.h b/src/lib/evas/include/evas_filter.h index c6854fd..edb12cd 100644 --- a/src/lib/evas/include/evas_filter.h +++ b/src/lib/evas/include/evas_filter.h @@ -32,7 +32,6 @@ # endif #endif /* ! _WIN32 */ -typedef struct _Evas_Filter_Context Evas_Filter_Context; typedef struct _Evas_Filter_Instruction Evas_Filter_Instruction; typedef struct _Evas_Filter_Buffer Evas_Filter_Buffer; typedef struct _Evas_Filter_Proxy_Binding Evas_Filter_Proxy_Binding; @@ -146,19 +145,22 @@ void evas_filter_program_data_set_all(Evas_Filter_Program *p Evas_Filter_Context *evas_filter_context_new(Evas_Public_Data *evas, Eina_Bool async, void *user_data); void *evas_filter_context_data_get(Evas_Filter_Context *ctx); Eina_Bool evas_filter_context_async_get(Evas_Filter_Context *ctx); +void evas_filter_context_size_get(Evas_Filter_Context *ctx, int *w, int *H); void evas_filter_context_destroy(Evas_Filter_Context *ctx); -Eina_Bool evas_filter_context_program_use(Evas_Filter_Context *ctx, Evas_Filter_Program *pgm); +Eina_Bool evas_filter_context_program_use(Evas_Filter_Context *ctx, Evas_Filter_Program *pgm, Eina_Bool reuse); +Eina_Bool evas_filter_context_program_reuse(Evas_Filter_Context *ctx, Evas_Filter_Program *pgm); void evas_filter_context_proxy_render_all(Evas_Filter_Context *ctx, Eo *eo_obj, Eina_Bool do_async); 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); void evas_filter_context_obscured_region_set(Evas_Filter_Context *ctx, Eina_Rectangle rect); -int evas_filter_buffer_empty_new(Evas_Filter_Context *ctx, Eina_Bool alpha_only); +int evas_filter_buffer_empty_new(Evas_Filter_Context *ctx, int w, int h, Eina_Bool alpha_only); +int evas_filter_buffer_proxy_new(Evas_Filter_Context *ctx, Evas_Filter_Proxy_Binding *pb, int *w, int *h); void *evas_filter_buffer_backing_get(Evas_Filter_Context *ctx, int bufid, Eina_Bool render); Eina_Bool evas_filter_buffer_backing_release(Evas_Filter_Context *ctx, void *stolen_buffer); -Eina_Bool evas_filter_run(Evas_Filter_Context *ctx); +Eina_Bool evas_filter_context_run(Evas_Filter_Context *ctx); 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 evas_filter_target_set(Evas_Filter_Context *ctx, void *draw_context, void *surface, int x, int y); diff --git a/src/lib/evas/include/evas_private.h b/src/lib/evas/include/evas_private.h index cd56838..6a0c776 100644 --- a/src/lib/evas/include/evas_private.h +++ b/src/lib/evas/include/evas_private.h @@ -93,6 +93,7 @@ typedef struct _Evas_Object_Protected_Data Evas_Object_Protected_Data; /* gfx filters typedef only */ typedef struct _Evas_Filter_Program Evas_Filter_Program; +typedef struct _Evas_Filter_Context Evas_Filter_Context; typedef struct _Evas_Object_Filter_Data Evas_Object_Filter_Data; typedef struct _Evas_Filter_Data_Binding Evas_Filter_Data_Binding; typedef struct _Evas_Pointer_Data Evas_Pointer_Data; @@ -1288,6 +1289,7 @@ struct _Evas_Object_Filter_Data Eina_Stringshare *name; Eina_Stringshare *code; Evas_Filter_Program *chain; + Evas_Filter_Context *context; Eina_Hash *sources; // Evas_Filter_Proxy_Binding Eina_Inlist *data; // Evas_Filter_Data_Binding Eina_Rectangle prev_obscured, obscured; @@ -1306,6 +1308,7 @@ struct _Evas_Object_Filter_Data Eina_Bool changed : 1; Eina_Bool invalid : 1; // Code parse failed Eina_Bool async : 1; + Eina_Bool reuse : 1; }; struct _Evas_Object_Func --
