summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJean-Philippe Andre <jp.andre@samsung.com>2017-09-04 19:08:02 +0900
committerJean-Philippe Andre <jp.andre@samsung.com>2017-09-06 09:54:47 +0900
commit9c9e5040414d74dc38b794084ea0374bd056b970 (patch)
tree3b248e793e957517e86d9c079aab286e9f0d0919
parent06d752b6327132ea54762cc3e676dbb0749b43c0 (diff)
downloadefl-9c9e5040414d74dc38b794084ea0374bd056b970.tar.gz
filters: Safety++
This is an attempt at fixing crashes in empc. Test scenario: ELM_ACCEL="" elementary_test -to "Gfx Filters" And mouse scroll like crazy in the spinner. @fix
-rw-r--r--src/lib/evas/canvas/evas_filter_mixin.c25
-rw-r--r--src/lib/evas/canvas/evas_object_textblock.c26
-rw-r--r--src/lib/evas/filters/evas_filter.c48
-rw-r--r--src/lib/evas/filters/evas_filter_private.h4
-rw-r--r--src/lib/evas/include/evas_filter.h4
5 files changed, 71 insertions, 36 deletions
diff --git a/src/lib/evas/canvas/evas_filter_mixin.c b/src/lib/evas/canvas/evas_filter_mixin.c
index ab9a8191d0..c6d1f328f5 100644
--- a/src/lib/evas/canvas/evas_filter_mixin.c
+++ b/src/lib/evas/canvas/evas_filter_mixin.c
@@ -120,13 +120,13 @@ _filter_end_sync(Evas_Filter_Context *ctx, Evas_Object_Protected_Data *obj,
if (previous)
ENFN->image_free(ENC, previous);
- if (destroy)
+ if (destroy && (ctx == pd->data->context))
{
- evas_filter_context_destroy(ctx);
- ctx = NULL;
+ evas_filter_context_unref(ctx); // local ref
+ FCOW_WRITE(pd, context, NULL);
}
- FCOW_WRITE(pd, context, ctx);
+ evas_filter_context_unref(ctx); // run ref
efl_unref(eo_obj);
}
@@ -379,7 +379,7 @@ evas_filter_object_render(Eo *eo_obj, Evas_Object_Protected_Data *obj,
if ((!pd->data->reuse) || (was_async != do_async) ||
(prev_w != W) || (prev_h != H))
{
- evas_filter_context_destroy(filter);
+ evas_filter_context_unref(filter);
FCOW_WRITE(pd, context, NULL);
filter = NULL;
}
@@ -390,7 +390,7 @@ evas_filter_object_render(Eo *eo_obj, Evas_Object_Protected_Data *obj,
ok = evas_filter_context_program_use(filter, pd->data->chain, EINA_TRUE, X, Y);
if (!ok)
{
- evas_filter_context_destroy(filter);
+ evas_filter_context_unref(filter);
FCOW_WRITE(pd, context, NULL);
filter = NULL;
}
@@ -405,8 +405,9 @@ evas_filter_object_render(Eo *eo_obj, Evas_Object_Protected_Data *obj,
if (!filter || !ok)
{
ERR("Parsing failed?");
- evas_filter_context_destroy(filter);
+ evas_filter_context_unref(filter);
FCOW_WRITE(pd, invalid, EINA_TRUE);
+ FCOW_WRITE(pd, context, NULL);
return EINA_FALSE;
}
}
@@ -474,8 +475,8 @@ _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);
+ evas_filter_context_unref(fcow->context);
+ fcow->context = NULL;
// Parse filter program
evas_filter_program_del(fcow->chain);
@@ -710,6 +711,7 @@ EOLIAN static void
_efl_canvas_filter_internal_efl_object_destructor(Eo *eo_obj, Evas_Filter_Data *pd)
{
Evas_Object_Protected_Data *obj;
+ Evas_Object_Filter_Data *fcow;
Evas_Filter_Data_Binding *db;
Evas_Public_Data *e;
Eina_Inlist *il;
@@ -721,7 +723,10 @@ _efl_canvas_filter_internal_efl_object_destructor(Eo *eo_obj, Evas_Filter_Data *
e = obj->layer->evas;
if (pd->data->context)
- evas_filter_context_destroy(pd->data->context);
+ {
+ evas_filter_context_unref(pd->data->context);
+ FCOW_WRITE(pd, context, NULL);
+ }
if (pd->data->output)
{
diff --git a/src/lib/evas/canvas/evas_object_textblock.c b/src/lib/evas/canvas/evas_object_textblock.c
index a7a7a78f90..6f3941eb9b 100644
--- a/src/lib/evas/canvas/evas_object_textblock.c
+++ b/src/lib/evas/canvas/evas_object_textblock.c
@@ -1042,7 +1042,11 @@ _item_free(const Evas_Object *eo_obj, Evas_Object_Textblock_Line *ln, Evas_Objec
ti->gfx_filter = NULL;
}
else
- ti->gfx_filter->ti = NULL;
+ {
+ evas_filter_context_unref(ti->gfx_filter->ctx);
+ ti->gfx_filter->ctx = NULL;
+ ti->gfx_filter->ti = NULL;
+ }
}
}
else
@@ -12943,6 +12947,7 @@ evas_object_textblock_free(Evas_Object *eo_obj)
EINA_INLIST_FREE(o->gfx_filter.programs, prg)
{
EINA_INLIST_REMOVE(o->gfx_filter.programs, prg);
+ evas_filter_program_del(prg->pgm);
eina_stringshare_del(prg->name);
eina_stringshare_del(prg->code);
free(prg);
@@ -13013,13 +13018,20 @@ _filter_sync_end(Evas_Filter_Context *ctx, Eina_Bool success)
if (filter->ti->parent.format->gfx_filter)
filter->ti->parent.format->gfx_filter->invalid = !success;
// else just avoid sigsegv
- filter->ctx = NULL;
+ if (filter->ctx == ctx)
+ {
+ // release local ref
+ evas_filter_context_unref(ctx);
+ filter->ctx = NULL;
+ }
}
else
{
free(filter);
}
- evas_filter_context_destroy(ctx);
+
+ // release run ref
+ evas_filter_context_unref(ctx);
}
static void
@@ -13136,7 +13148,7 @@ evas_object_textblock_render(Evas_Object *eo_obj EINA_UNUSED,
Eina_List *shadows = NULL;
Eina_List *glows = NULL;
Eina_List *outlines = NULL;
- Eina_List *gfx_filters = NULL, *li;
+ Eina_List *gfx_filters = NULL;
void *context_save = context;
int strikethrough_thickness, underline_thickness, underline_position;
int i, j;
@@ -13426,7 +13438,7 @@ evas_object_textblock_render(Evas_Object *eo_obj EINA_UNUSED,
* in "_text_item_update_sizes" should not modify one without the other. */
/* gfx filters preparation */
- EINA_LIST_FOREACH(gfx_filters, li, itr)
+ EINA_LIST_FREE(gfx_filters, itr)
{
Efl_Canvas_Filter_State state = EFL_CANVAS_FILTER_STATE_DEFAULT;
Evas_Object_Textblock_Text_Item *ti = _ITEM_TEXT(itr);
@@ -13487,7 +13499,7 @@ evas_object_textblock_render(Evas_Object *eo_obj EINA_UNUSED,
ok = evas_filter_context_program_use(ctx, pgm, EINA_FALSE, 0, 0);
if (!ok)
{
- evas_filter_context_destroy(ctx);
+ evas_filter_context_unref(ctx);
filter->invalid = EINA_TRUE;
continue;
}
@@ -13502,6 +13514,8 @@ evas_object_textblock_render(Evas_Object *eo_obj EINA_UNUSED,
evas_filter_context_proxy_render_all(ctx, eo_obj, EINA_FALSE);
evas_filter_context_buffers_allocate_all(ctx);
evas_filter_target_set(ctx, context, surface, target.x, target.y, NULL);
+ if (ti->gfx_filter->ctx)
+ evas_filter_context_unref(ti->gfx_filter->ctx);
ti->gfx_filter->ctx = ctx;
ti->gfx_filter->do_async = do_async;
diff --git a/src/lib/evas/filters/evas_filter.c b/src/lib/evas/filters/evas_filter.c
index 18969ecaaa..066555b383 100644
--- a/src/lib/evas/filters/evas_filter.c
+++ b/src/lib/evas/filters/evas_filter.c
@@ -38,6 +38,9 @@ static void _filter_buffer_unlock_all(Evas_Filter_Context *ctx);
/* Main functions */
+#define _free(ptr) free(ptr)
+//eina_freeq_ptr_main_add(ptr, NULL, sizeof(*ptr))
+
Evas_Filter_Context *
evas_filter_context_new(Evas_Public_Data *evas, Eina_Bool async, void *user_data)
{
@@ -55,6 +58,7 @@ evas_filter_context_new(Evas_Public_Data *evas, Eina_Bool async, void *user_data
ctx->user_data = user_data;
ctx->buffer_scaled_get = &evas_filter_buffer_scaled_get;
ctx->gl = (ENFN->gl_surface_read_pixels != NULL);
+ ctx->refcount = 1;
return ctx;
}
@@ -205,26 +209,39 @@ _context_destroy(void *data)
{
Evas_Filter_Context *ctx = data;
+ EINA_SAFETY_ON_FALSE_RETURN(ctx->refcount == 0);
evas_filter_context_clear(ctx, EINA_FALSE);
- free(ctx);
+ _free(ctx);
+}
+
+int
+evas_filter_context_ref(Evas_Filter_Context *ctx)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, -1);
+
+#ifdef FILTERS_DEBUG
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(eina_main_loop_is(), -1);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(ctx->refcount > 0, -1);
+#endif
+
+ return (++ctx->refcount);
}
void
-evas_filter_context_destroy(Evas_Filter_Context *ctx)
+evas_filter_context_unref(Evas_Filter_Context *ctx)
{
if (!ctx) return;
#ifdef FILTERS_DEBUG
EINA_SAFETY_ON_FALSE_RETURN(eina_main_loop_is());
+ EINA_SAFETY_ON_FALSE_RETURN(ctx->refcount > 0);
#endif
- if (ctx->delete_me) return;
- ctx->delete_me = EINA_TRUE;
+ if ((--ctx->refcount) != 0) return;
- if (ctx->running)
- evas_post_render_job_add(ctx->evas, _context_destroy, ctx);
- else
+ if (!ctx->running)
_context_destroy(ctx);
+ // else: post_run_cb will be called
}
void
@@ -509,7 +526,7 @@ _buffer_alloc_new(Evas_Filter_Context *ctx, int w, int h, Eina_Bool alpha_only,
if (!fb->buffer)
{
ERR("Failed to create ector buffer!");
- free(fb);
+ _free(fb);
return NULL;
}
@@ -523,7 +540,7 @@ _buffer_free(Evas_Filter_Buffer *fb)
_filter_buffer_backing_free(fb);
eina_stringshare_del(fb->source_name);
efl_unref(fb->source);
- free(fb);
+ _free(fb);
}
Evas_Filter_Buffer *
@@ -627,10 +644,10 @@ _command_del(Evas_Filter_Context *ctx, Evas_Filter_Command *cmd)
ctx->commands = eina_inlist_remove(ctx->commands, EINA_INLIST_GET(cmd));
switch (cmd->mode)
{
- case EVAS_FILTER_MODE_CURVE: free(cmd->curve.data); break;
+ case EVAS_FILTER_MODE_CURVE: _free(cmd->curve.data); break;
default: break;
}
- free(cmd);
+ _free(cmd);
}
Evas_Filter_Buffer *
@@ -1334,7 +1351,7 @@ evas_filter_command_curve_add(Evas_Filter_Context *ctx,
cmd = _command_new(ctx, EVAS_FILTER_MODE_CURVE, in, NULL, out);
if (!cmd)
{
- free(copy);
+ _free(copy);
return NULL;
}
@@ -1559,7 +1576,7 @@ evas_filter_target_set(Evas_Filter_Context *ctx, void *draw_context,
ctx->target.color_use = EINA_FALSE;
ctx->target.rop = ENFN->context_render_op_get(ENDT, draw_context);
- free(ctx->target.map);
+ _free(ctx->target.map);
if (!map) ctx->target.map = NULL;
else
{
@@ -1820,9 +1837,7 @@ end:
ctx->running = EINA_FALSE;
DEBUG_TIME_END();
- if (ctx->post_run.cb)
- ctx->post_run.cb(ctx, ctx->post_run.data, ok);
-
+ ctx->post_run.cb(ctx, ctx->post_run.data, ok);
return ok;
}
@@ -1884,6 +1899,7 @@ _filter_obscured_region_calc(Evas_Filter_Context *ctx)
Eina_Bool
evas_filter_context_run(Evas_Filter_Context *ctx)
{
+ evas_filter_context_ref(ctx);
_filter_obscured_region_calc(ctx);
ctx->run_count++;
diff --git a/src/lib/evas/filters/evas_filter_private.h b/src/lib/evas/filters/evas_filter_private.h
index f6faea3838..ab5bc376af 100644
--- a/src/lib/evas/filters/evas_filter_private.h
+++ b/src/lib/evas/filters/evas_filter_private.h
@@ -163,10 +163,10 @@ struct _Evas_Filter_Context
Eina_Bool color_use : 1;
} target;
- int run_count;
+ short run_count;
+ short refcount;
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 3f88970dc0..c0742b1a1d 100644
--- a/src/lib/evas/include/evas_filter.h
+++ b/src/lib/evas/include/evas_filter.h
@@ -150,11 +150,11 @@ Evas_Filter_Context *evas_filter_context_new(Evas_Public_Data *evas, Eina_Bo
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);
+int evas_filter_context_ref(Evas_Filter_Context *ctx);
+void evas_filter_context_unref(Evas_Filter_Context *ctx);
Eina_Bool evas_filter_context_program_use(Evas_Filter_Context *ctx, Evas_Filter_Program *pgm, Eina_Bool reuse, int object_x, int object_y);
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);