jpeg pushed a commit to branch master. http://git.enlightenment.org/core/efl.git/commit/?id=3c92b32c13b11c492f9b0b6d2c60660b8add3468
commit 3c92b32c13b11c492f9b0b6d2c60660b8add3468 Author: Jean-Philippe Andre <jp.an...@samsung.com> Date: Thu Apr 13 12:08:31 2017 +0900 evas filters: Fix async RW rendering This fixes a crash (when deleting the output image), and rearranges the code a bit. --- src/lib/evas/canvas/evas_filter_mixin.c | 389 ++++++++++++++--------------- src/lib/evas/canvas/evas_object_image.c | 3 +- src/lib/evas/filters/evas_filter.c | 46 ++-- src/lib/evas/filters/evas_filter_private.h | 7 +- src/lib/evas/include/evas_filter.h | 5 +- 5 files changed, 207 insertions(+), 243 deletions(-) diff --git a/src/lib/evas/canvas/evas_filter_mixin.c b/src/lib/evas/canvas/evas_filter_mixin.c index 742a9e8..ee38291 100644 --- a/src/lib/evas/canvas/evas_filter_mixin.c +++ b/src/lib/evas/canvas/evas_filter_mixin.c @@ -120,14 +120,9 @@ _filter_end_sync(Evas_Filter_Context *ctx, Evas_Object_Protected_Data *obj, FCOW_WRITE(pd, output, output); } - if (EINA_UNLIKELY(ctx != pd->data->context)) - { - ERR("Filter context has changed! Destroying it now..."); - evas_filter_context_destroy(pd->data->context); - destroy = EINA_TRUE; - } + if (previous) + ENFN->image_free(ENDT, previous); - evas_filter_buffer_backing_release(ctx, previous); if (destroy) { evas_filter_context_destroy(ctx); @@ -143,7 +138,7 @@ _filter_async_post_render_cb(void *data) Evas_Filter_Post_Render_Data *task = data; Evas_Filter_Data *pd = task->pd; -#ifdef DEBUG +#ifdef FILTERS_DEBUG EINA_SAFETY_ON_FALSE_RETURN(eina_main_loop_is()); #endif @@ -158,12 +153,8 @@ _filter_cb(Evas_Filter_Context *ctx, void *data, Eina_Bool success) Evas_Object_Protected_Data *obj; Evas_Filter_Data *pd = data; -#ifdef DEBUG - EINA_SAFETY_ON_FALSE_RETURN(!eina_main_loop_is()); -#endif - obj = pd->data->obj; - EINA_SAFETY_ON_FALSE_RETURN(obj && obj->layer && obj->layer->evas); + EVAS_OBJECT_DATA_VALID_CHECK(obj); if (!pd->data->async) { @@ -171,6 +162,10 @@ _filter_cb(Evas_Filter_Context *ctx, void *data, Eina_Bool success) return; } +#ifdef FILTERS_DEBUG + EINA_SAFETY_ON_FALSE_RETURN(!eina_main_loop_is()); +#endif + post_data = calloc(1, sizeof(*post_data)); post_data->success = success; post_data->ctx = ctx; @@ -252,234 +247,220 @@ evas_filter_object_render(Eo *eo_obj, Evas_Object_Protected_Data *obj, int x, int y, Eina_Bool do_async, Eina_Bool alpha) { Evas_Filter_Data *pd = efl_data_scope_get(eo_obj, MY_CLASS); + int X, Y, W, H; + Evas_Filter_Context *filter; + void *drawctx; + Eina_Bool ok; + void *previous = pd->data->output; + Evas_Object_Filter_Data *fcow; + Eina_Bool use_map = EINA_FALSE; + Evas_Filter_Padding pad; - if (!pd->data->invalid && (pd->data->chain || pd->data->code)) - { - int X, Y, W, H; - Evas_Filter_Context *filter; - void *drawctx; - Eina_Bool ok; - void *previous = pd->data->output; - Evas_Object_Filter_Data *fcow; - Eina_Bool use_map = EINA_FALSE; - Evas_Filter_Padding pad; - - W = obj->cur->geometry.w; - H = obj->cur->geometry.h; - X = obj->cur->geometry.x; - Y = obj->cur->geometry.y; - - // Prepare color multiplier - ENFN->context_color_set(output, context, - obj->cur->cache.clip.r, - obj->cur->cache.clip.g, - obj->cur->cache.clip.b, - obj->cur->cache.clip.a); - if (obj->cur->clipper) - ENFN->context_multiplier_set(output, context, - obj->cur->clipper->cur->cache.clip.r, - obj->cur->clipper->cur->cache.clip.g, - obj->cur->clipper->cur->cache.clip.b, - obj->cur->clipper->cur->cache.clip.a); - else - ENFN->context_multiplier_unset(output, context); + if (pd->data->invalid || (!pd->data->chain && !pd->data->code)) + return EINA_FALSE; - if (obj->map->cur.usemap && obj->map->cur.map && (obj->map->cur.map->count >= 4)) - { - int iw, ih; + W = obj->cur->geometry.w; + H = obj->cur->geometry.h; + X = obj->cur->geometry.x; + Y = obj->cur->geometry.y; + + // Prepare color multiplier + ENFN->context_color_set(output, context, + obj->cur->cache.clip.r, + obj->cur->cache.clip.g, + obj->cur->cache.clip.b, + obj->cur->cache.clip.a); + if (obj->cur->clipper) + ENFN->context_multiplier_set(output, context, + obj->cur->clipper->cur->cache.clip.r, + obj->cur->clipper->cur->cache.clip.g, + obj->cur->clipper->cur->cache.clip.b, + obj->cur->clipper->cur->cache.clip.a); + else + ENFN->context_multiplier_unset(output, context); - use_map = EINA_TRUE; - ENFN->image_size_get(ENDT, previous, &iw, &ih); - evas_object_map_update(eo_obj, x, y, iw, ih, iw, ih); - } + if (obj->map->cur.usemap && obj->map->cur.map && (obj->map->cur.map->count >= 4)) + { + int iw, ih; + + use_map = EINA_TRUE; + ENFN->image_size_get(ENDT, previous, &iw, &ih); + evas_object_map_update(eo_obj, x, y, iw, ih, iw, ih); + } - if (!pd->data->chain) + if (!pd->data->chain) + { + Evas_Filter_Program *pgm; + Eina_Bool invalid; + + pgm = evas_filter_program_new(pd->data->name, alpha); + evas_filter_program_source_set_all(pgm, pd->data->sources); + evas_filter_program_data_set_all(pgm, pd->data->data); + _evas_filter_state_set_internal(pgm, pd); + invalid = !evas_filter_program_parse(pgm, pd->data->code); + if (invalid) { - Evas_Filter_Program *pgm; - Eina_Bool invalid; - - pgm = evas_filter_program_new(pd->data->name, alpha); - evas_filter_program_source_set_all(pgm, pd->data->sources); - evas_filter_program_data_set_all(pgm, pd->data->data); - _evas_filter_state_set_internal(pgm, pd); - invalid = !evas_filter_program_parse(pgm, pd->data->code); - if (invalid) - { - ERR("Filter program parsing failed"); - evas_filter_program_del(pgm); - pgm = NULL; - } - fcow = FCOW_BEGIN(pd); - if (!invalid) evas_filter_program_padding_get(pgm, NULL, &fcow->padding); - fcow->chain = pgm; - fcow->invalid = invalid; - FCOW_END(fcow, pd); - if (invalid) return EINA_FALSE; + ERR("Filter program parsing failed"); + evas_filter_program_del(pgm); + pgm = NULL; } - else if (previous && !pd->data->changed) + fcow = FCOW_BEGIN(pd); + if (!invalid) evas_filter_program_padding_get(pgm, NULL, &fcow->padding); + fcow->chain = pgm; + fcow->invalid = invalid; + FCOW_END(fcow, pd); + if (invalid) return EINA_FALSE; + } + else if (previous && !pd->data->changed) + { + Eina_Bool redraw = EINA_TRUE; + + if (_evas_filter_state_set_internal(pd->data->chain, pd)) + DBG("Filter redraw by state change!"); + else if (obj->changed) + DBG("Filter redraw by object content change!"); + else if (obj->snapshot_needs_redraw) + DBG("Filter redraw by snapshot change!"); + else if (_evas_filter_obscured_region_changed(pd)) + DBG("Filter redraw by obscure regions change!"); + else redraw = EINA_FALSE; + + // Scan proxies to find if any changed + if (!redraw && pd->data->sources) { - Eina_Bool redraw = EINA_TRUE; - - if (_evas_filter_state_set_internal(pd->data->chain, pd)) - DBG("Filter redraw by state change!"); - else if (obj->changed) - DBG("Filter redraw by object content change!"); - else if (obj->snapshot_needs_redraw) - DBG("Filter redraw by snapshot change!"); - else if (_evas_filter_obscured_region_changed(pd)) - DBG("Filter redraw by obscure regions change!"); - else redraw = EINA_FALSE; - - // Scan proxies to find if any changed - if (!redraw && pd->data->sources) - { - Evas_Filter_Proxy_Binding *pb; - Evas_Object_Protected_Data *source; - Eina_Iterator *iter; + Evas_Filter_Proxy_Binding *pb; + Evas_Object_Protected_Data *source; + Eina_Iterator *iter; - iter = eina_hash_iterator_data_new(pd->data->sources); - EINA_ITERATOR_FOREACH(iter, pb) - { - source = efl_data_scope_get(pb->eo_source, EFL_CANVAS_OBJECT_CLASS); - if (source->changed) - { - redraw = EINA_TRUE; - break; - } - } - eina_iterator_free(iter); - } - - if (!redraw) + iter = eina_hash_iterator_data_new(pd->data->sources); + EINA_ITERATOR_FOREACH(iter, pb) { - // Render this image only - if (use_map) - { - ENFN->image_map_draw(ENDT, context, surface, previous, - obj->map->spans, EINA_TRUE, 0, do_async); - } - else + source = efl_data_scope_get(pb->eo_source, EFL_CANVAS_OBJECT_CLASS); + if (source->changed) { - ENFN->image_draw(ENDT, context, - surface, previous, - 0, 0, W, H, // src - X + x, Y + y, W, H, // dst - EINA_FALSE, // smooth - do_async); + redraw = EINA_TRUE; + break; } - return EINA_TRUE; } - } - else - { - _evas_filter_state_set_internal(pd->data->chain, pd); + eina_iterator_free(iter); } - filter = pd->data->context; - if (filter) + if (!redraw) { - int prev_w, prev_h; - Eina_Bool was_async; - - 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)) + // Render this image only + if (use_map) + { + ENFN->image_map_draw(ENDT, context, surface, previous, + obj->map->spans, EINA_TRUE, 0, do_async); + } + else { - fcow = FCOW_BEGIN(pd); - fcow->context = NULL; - FCOW_END(fcow, pd); - evas_filter_context_destroy(filter); - filter = NULL; + ENFN->image_draw(ENDT, context, + surface, previous, + 0, 0, W, H, // src + X + x, Y + y, W, H, // dst + EINA_FALSE, // smooth + do_async); } + return EINA_TRUE; } + } + else + { + _evas_filter_state_set_internal(pd->data->chain, pd); + } + + filter = pd->data->context; + if (filter) + { + int prev_w, prev_h; + Eina_Bool was_async; - if (filter) + 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)) { - ok = evas_filter_context_program_use(filter, pd->data->chain, EINA_TRUE, X, Y); - if (!ok) - { - fcow = FCOW_BEGIN(pd); - fcow->context = NULL; - FCOW_END(fcow, pd); - evas_filter_context_destroy(filter); - filter = NULL; - } + evas_filter_context_destroy(filter); + FCOW_WRITE(pd, context, NULL); + filter = NULL; } + } - if (!filter) + if (filter) + { + ok = evas_filter_context_program_use(filter, pd->data->chain, EINA_TRUE, X, Y); + if (!ok) { - filter = evas_filter_context_new(obj->layer->evas, do_async, 0); + evas_filter_context_destroy(filter); + FCOW_WRITE(pd, context, NULL); + filter = NULL; + } + } - // Run script - ok = evas_filter_context_program_use(filter, pd->data->chain, EINA_FALSE, X, Y); - if (!filter || !ok) - { - ERR("Parsing failed?"); - evas_filter_context_destroy(filter); + if (!filter) + { + filter = evas_filter_context_new(obj->layer->evas, do_async, 0); - if (!pd->data->invalid) - { - fcow = FCOW_BEGIN(pd); - fcow->invalid = EINA_TRUE; - FCOW_END(fcow, pd); - } - return EINA_FALSE; - } + // Run script + ok = evas_filter_context_program_use(filter, pd->data->chain, EINA_FALSE, X, Y); + if (!filter || !ok) + { + ERR("Parsing failed?"); + evas_filter_context_destroy(filter); + FCOW_WRITE(pd, invalid, EINA_TRUE); + return EINA_FALSE; } + } + + // Proxies + evas_filter_context_proxy_render_all(filter, eo_obj, EINA_FALSE); - // Proxies - evas_filter_context_proxy_render_all(filter, eo_obj, EINA_FALSE); + // Draw Context + drawctx = ENFN->context_new(ENDT); + ENFN->context_color_set(ENDT, drawctx, 255, 255, 255, 255); - // Draw Context - drawctx = ENFN->context_new(ENDT); - ENFN->context_color_set(ENDT, drawctx, 255, 255, 255, 255); + // Set obscured region + evas_filter_context_obscured_region_set(filter, pd->data->obscured); - // Set obscured region - evas_filter_context_obscured_region_set(filter, pd->data->obscured); + // Allocate all buffers now + evas_filter_context_buffers_allocate_all(filter); + evas_filter_target_set(filter, context, surface, X + x, Y + y, + use_map ? obj->map->spans : NULL); - // Allocate all buffers now - evas_filter_context_buffers_allocate_all(filter); - evas_filter_target_set(filter, context, surface, X + x, Y + y, - use_map ? obj->map->spans : NULL); + // Request rendering from the object itself (child class) + evas_filter_program_padding_get(pd->data->chain, &pad, NULL); + ok = evas_filter_input_render(eo_obj, filter, drawctx, NULL, pad.l, pad.r, pad.t, pad.b, 0, 0, do_async); + if (!ok) ERR("Filter input render failed."); - // Request rendering from the object itself (child class) - evas_filter_program_padding_get(pd->data->chain, &pad, NULL); - ok = evas_filter_input_render(eo_obj, filter, drawctx, NULL, pad.l, pad.r, pad.t, pad.b, 0, 0, do_async); - if (!ok) ERR("Filter input render failed."); + ENFN->context_free(ENDT, drawctx); - ENFN->context_free(ENDT, drawctx); + // Add post-run callback and run filter + evas_filter_context_post_run_callback_set(filter, _filter_cb, pd); - // Add post-run callback and run filter - evas_filter_context_post_run_callback_set(filter, _filter_cb, pd); + fcow = FCOW_BEGIN(pd); + fcow->context = filter; + fcow->changed = EINA_FALSE; + fcow->async = do_async; + fcow->prev_obscured = fcow->obscured; + fcow->prev_padding = fcow->padding; + fcow->padding = pad; + fcow->invalid = EINA_FALSE; + FCOW_END(fcow, pd); + // Run the filter now (maybe async) + ok = evas_filter_context_run(filter); + if (!ok) + { + ERR("Filter program failed to run!"); + evas_filter_context_destroy(filter); fcow = FCOW_BEGIN(pd); - fcow->context = filter; - fcow->changed = EINA_FALSE; - fcow->async = do_async; - fcow->prev_obscured = fcow->obscured; - fcow->prev_padding = fcow->padding; - fcow->padding = pad; - fcow->invalid = EINA_FALSE; + fcow->context = NULL; + fcow->invalid = EINA_TRUE; FCOW_END(fcow, pd); - - ok = evas_filter_context_run(filter); - - if (ok) - { - DBG("Effect rendering done."); - return EINA_TRUE; - } - else - { - fcow = FCOW_BEGIN(pd); - fcow->invalid = EINA_TRUE; - FCOW_END(fcow, pd); - ERR("Rendering failed."); - return EINA_FALSE; - } } - return EINA_FALSE; + + return ok; } EOLIAN static void diff --git a/src/lib/evas/canvas/evas_object_image.c b/src/lib/evas/canvas/evas_object_image.c index 41ed31d..1fb8b0d 100644 --- a/src/lib/evas/canvas/evas_object_image.c +++ b/src/lib/evas/canvas/evas_object_image.c @@ -1798,8 +1798,7 @@ _efl_canvas_image_internal_efl_canvas_filter_internal_filter_input_render( l, t, r, b, EINA_TRUE, do_async); ENFN->context_free(output, ctx); - - evas_filter_buffer_backing_release(filter, surface); + ENFN->image_free(output, surface); return EINA_TRUE; } diff --git a/src/lib/evas/filters/evas_filter.c b/src/lib/evas/filters/evas_filter.c index 988fbe5..1e73bb3 100644 --- a/src/lib/evas/filters/evas_filter.c +++ b/src/lib/evas/filters/evas_filter.c @@ -212,7 +212,15 @@ _context_destroy(void *data) void evas_filter_context_destroy(Evas_Filter_Context *ctx) { - // FIXME: This is not locked... + if (!ctx) return; + +#ifdef FILTERS_DEBUG + EINA_SAFETY_ON_FALSE_RETURN(eina_main_loop_is()); +#endif + + if (ctx->delete_me) return; + ctx->delete_me = EINA_TRUE; + if (ctx->running) evas_post_render_job_add(ctx->evas, _context_destroy, ctx); else @@ -577,18 +585,6 @@ end: return ret; } -Eina_Bool -evas_filter_buffer_backing_release(Evas_Filter_Context *ctx, - void *stolen_buffer) -{ - if (!stolen_buffer) return EINA_FALSE; - EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, EINA_FALSE); - EINA_SAFETY_ON_FALSE_RETURN_VAL(eina_main_loop_is(), EINA_FALSE); - - ENFN->image_free(ENDT, stolen_buffer); // ref-- - return EINA_TRUE; -} - static Evas_Filter_Command * _command_new(Evas_Filter_Context *ctx, Evas_Filter_Mode mode, Evas_Filter_Buffer *input, Evas_Filter_Buffer *mask, @@ -1820,19 +1816,16 @@ end: ctx->running = EINA_FALSE; DEBUG_TIME_END(); + if (ctx->post_run.cb) + ctx->post_run.cb(ctx, ctx->post_run.data, ok); + return ok; } static void _filter_thread_run_cb(void *data) { - Evas_Filter_Context *ctx = data; - Eina_Bool success; - - success = _filter_chain_run(ctx); - - if (ctx->post_run.cb) - ctx->post_run.cb(ctx, ctx->post_run.data, success); + _filter_chain_run(data); } static void @@ -1887,15 +1880,11 @@ _filter_obscured_region_calc(Evas_Filter_Context *ctx) Eina_Bool evas_filter_context_run(Evas_Filter_Context *ctx) { - Eina_Bool ret; - EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, EINA_FALSE); - if (!ctx->commands) - return EINA_TRUE; - _filter_obscured_region_calc(ctx); + ctx->run_count++; ctx->running = EINA_TRUE; if (ctx->async) { @@ -1903,12 +1892,7 @@ evas_filter_context_run(Evas_Filter_Context *ctx) return EINA_TRUE; } - ctx->run_count++; - ret = _filter_chain_run(ctx); - - if (ctx->post_run.cb) - ctx->post_run.cb(ctx, ctx->post_run.data, ret); - return ret; + return _filter_chain_run(ctx); } diff --git a/src/lib/evas/filters/evas_filter_private.h b/src/lib/evas/filters/evas_filter_private.h index df02000..8ced3d8 100644 --- a/src/lib/evas/filters/evas_filter_private.h +++ b/src/lib/evas/filters/evas_filter_private.h @@ -8,10 +8,6 @@ extern int _evas_filter_log_dom; #define EVAS_FILTER_LOG_COLOR EINA_COLOR_LIGHTBLUE -//#ifdef DEBUG -# define FILTERS_DEBUG -//#endif - #ifdef ERR # undef ERR #endif @@ -159,9 +155,10 @@ struct _Evas_Filter_Context Eina_Bool color_use : 1; } target; - volatile int running; int run_count; + Eina_Bool running : 1; + Eina_Bool delete_me : 1; Eina_Bool async : 1; Eina_Bool has_proxies : 1; Eina_Bool gl : 1; diff --git a/src/lib/evas/include/evas_filter.h b/src/lib/evas/include/evas_filter.h index f273064..3c1ae71 100644 --- a/src/lib/evas/include/evas_filter.h +++ b/src/lib/evas/include/evas_filter.h @@ -32,6 +32,10 @@ # endif #endif /* ! _WIN32 */ +//#ifdef DEBUG +# define FILTERS_DEBUG +//#endif + 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; @@ -158,7 +162,6 @@ int evas_filter_buffer_empty_new(Evas_Filter_Context *ctx, 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_set(Evas_Filter_Context *ctx, int bufid, void *engine_buffer); -Eina_Bool evas_filter_buffer_backing_release(Evas_Filter_Context *ctx, void *stolen_buffer); Eina_Bool evas_filter_context_run(Evas_Filter_Context *ctx); --