From a9227fd5306ba68d020623121f3efd3f17857c76 Mon Sep 17 00:00:00 2001 From: Cedric Bail Date: Thu, 31 Oct 2019 13:20:52 -0400 Subject: [PATCH] evas: move watching over destruction of device to custom logic due to high use. Summary: This specific EFL_EVENT_DEL handler was registered thousand of time alone on an Evas device. Potential solution are to improve handling of this kind of large scale callback logic or just not take that path. I find it easier to have a custom code in this case to handle the destruction of Evas device and avoid this thousand of callback. Depends on D10492 Reviewers: zmike, raster, bu5hm4n, Hermet Reviewed By: zmike Subscribers: #reviewers, #committers Tags: #efl Maniphest Tasks: T8321 Differential Revision: https://phab.enlightenment.org/D10493 --- src/lib/evas/Evas_Internal.h | 5 ++ src/lib/evas/canvas/efl_input_device.c | 42 +++++++++++ src/lib/evas/canvas/evas_object_main.c | 98 ++++++++++++-------------- src/lib/evas/include/evas_private.h | 6 ++ 4 files changed, 99 insertions(+), 52 deletions(-) diff --git a/src/lib/evas/Evas_Internal.h b/src/lib/evas/Evas_Internal.h index 782742f5d9..d631cdcde5 100644 --- a/src/lib/evas/Evas_Internal.h +++ b/src/lib/evas/Evas_Internal.h @@ -38,6 +38,8 @@ extern "C" { #include +typedef struct _Evas_Object_Pointer_Data Evas_Object_Pointer_Data; + EOAPI const Eina_List *efl_input_device_children_get(const Eo *obj); EOAPI void efl_input_device_evas_set(Eo *obj, Evas *e); @@ -46,6 +48,9 @@ EOAPI Evas *efl_input_device_evas_get(const Eo *obj); EOAPI void efl_input_device_subclass_set(Eo *obj, Evas_Device_Subclass sub_clas); EOAPI Evas_Device_Subclass efl_input_device_subclass_get(const Eo *obj); +EOAPI void efl_input_device_grab_register(Eo *obj, Efl_Canvas_Object *grab, Evas_Object_Pointer_Data *pdata); +EOAPI void efl_input_device_grab_unregister(Eo *obj, Efl_Canvas_Object *grab, Evas_Object_Pointer_Data *pdata); + typedef struct _Efl_Input_Pointer_Data Efl_Input_Pointer_Data; typedef struct _Efl_Input_Key_Data Efl_Input_Key_Data; typedef struct _Efl_Input_Hold_Data Efl_Input_Hold_Data; diff --git a/src/lib/evas/canvas/efl_input_device.c b/src/lib/evas/canvas/efl_input_device.c index 607ffd5f76..52eae92cbb 100644 --- a/src/lib/evas/canvas/efl_input_device.c +++ b/src/lib/evas/canvas/efl_input_device.c @@ -5,6 +5,8 @@ #include "Evas.h" #define EFL_INTERNAL_UNSTABLE #include "Evas_Internal.h" +#include "evas_common_private.h" +#include "evas_private.h" #define MY_CLASS EFL_INPUT_DEVICE_CLASS @@ -16,6 +18,9 @@ struct _Efl_Input_Device_Data Eo *evas; /* Evas */ Efl_Input_Device *source; /* ref */ Eina_List *children; /* ref'ed by efl_parent, not by this list */ + Eina_Hash *grabs; /* Hash of all the object that might grab this device. + We expect thousand of them to be registered here, + that is why we use a hash. */ unsigned int id; Efl_Input_Device_Type klass; unsigned int subclass; // Evas_Device_Subclass (unused) @@ -71,6 +76,12 @@ _efl_input_device_efl_object_destructor(Eo *obj, Efl_Input_Device_Data *pd) } efl_unref(pd->source); + if (pd->grabs) + { + eina_hash_free(pd->grabs); + pd->grabs = NULL; + } + return efl_destructor(efl_super(obj, MY_CLASS)); } @@ -279,11 +290,42 @@ _efl_input_device_subclass_set(Eo *obj EINA_UNUSED, Efl_Input_Device_Data *pd, EOAPI EFL_VOID_FUNC_BODYV(efl_input_device_subclass_set, EFL_FUNC_CALL(sub_clas), Evas_Device_Subclass sub_clas); +static void +_grab_del(void *data) +{ + Evas_Object_Pointer_Data *pdata = data; + + evas_object_pointer_grab_del(pdata->obj, pdata); +} + +static void +_efl_input_device_grab_register(Eo *obj EINA_UNUSED, Efl_Input_Device_Data *pd, + Efl_Canvas_Object *grab, Evas_Object_Pointer_Data *pdata) +{ + if (!pd->grabs) pd->grabs = eina_hash_pointer_new(_grab_del); + eina_hash_add(pd->grabs, &grab, pdata); +} + +EOAPI EFL_VOID_FUNC_BODYV(efl_input_device_grab_register, EFL_FUNC_CALL(grab, pdata), + Efl_Canvas_Object *grab, Evas_Object_Pointer_Data *pdata); + +static void +_efl_input_device_grab_unregister(Eo *obj EINA_UNUSED, Efl_Input_Device_Data *pd, + Efl_Canvas_Object *grab, Evas_Object_Pointer_Data *pdata) +{ + eina_hash_del(pd->grabs, &grab, pdata); +} + +EOAPI EFL_VOID_FUNC_BODYV(efl_input_device_grab_unregister, EFL_FUNC_CALL(grab, pdata), + Efl_Canvas_Object *grab, Evas_Object_Pointer_Data *pdata); + #define EFL_INPUT_DEVICE_EXTRA_OPS \ EFL_OBJECT_OP_FUNC(efl_input_device_evas_get, _efl_input_device_evas_get), \ EFL_OBJECT_OP_FUNC(efl_input_device_evas_set, _efl_input_device_evas_set), \ EFL_OBJECT_OP_FUNC(efl_input_device_subclass_get, _efl_input_device_subclass_get), \ EFL_OBJECT_OP_FUNC(efl_input_device_subclass_set, _efl_input_device_subclass_set), \ EFL_OBJECT_OP_FUNC(efl_input_device_children_get, _efl_input_device_children_get), \ + EFL_OBJECT_OP_FUNC(efl_input_device_grab_register, _efl_input_device_grab_register), \ + EFL_OBJECT_OP_FUNC(efl_input_device_grab_unregister, _efl_input_device_grab_unregister), #include "efl_input_device.eo.c" diff --git a/src/lib/evas/canvas/evas_object_main.c b/src/lib/evas/canvas/evas_object_main.c index 27ec6e2bfc..d5b20aed22 100644 --- a/src/lib/evas/canvas/evas_object_main.c +++ b/src/lib/evas/canvas/evas_object_main.c @@ -81,9 +81,9 @@ _init_cow(void) return EINA_TRUE; } -static Evas_Object_Pointer_Data * -_evas_object_pointer_data_find(Evas_Object_Protected_Data *obj, - Efl_Input_Device *pointer) +Evas_Object_Pointer_Data * +evas_object_pointer_data_find(Evas_Object_Protected_Data *obj, + Efl_Input_Device *pointer) { Evas_Object_Pointer_Data *pdata; @@ -95,22 +95,6 @@ _evas_object_pointer_data_find(Evas_Object_Protected_Data *obj, return NULL; } -static void -_evas_object_pointer_grab_del(Evas_Object_Protected_Data *obj, Evas_Object_Pointer_Data *pdata); - -static void -_evas_device_del_cb(void *data, const Efl_Event *ev) -{ - Evas_Object_Protected_Data *obj; - Evas_Object_Pointer_Data *pdata; - - obj = efl_data_scope_safe_get(data, MY_CLASS); - EINA_SAFETY_ON_NULL_RETURN(obj); - pdata = _evas_object_pointer_data_find(obj, ev->object); - if (!pdata) return; - _evas_object_pointer_grab_del(obj, pdata); -} - static void _evas_object_proxy_grab_del(Evas_Object_Protected_Data *obj, Evas_Object_Pointer_Data *pdata) @@ -138,9 +122,9 @@ _evas_object_proxy_grab_del(Evas_Object_Protected_Data *obj, } } -static void -_evas_object_pointer_grab_del(Evas_Object_Protected_Data *obj, - Evas_Object_Pointer_Data *pdata) +void +evas_object_pointer_grab_del(Evas_Object_Protected_Data *obj, + Evas_Object_Pointer_Data *pdata) { if ((pdata->mouse_grabbed > 0) && (obj->layer) && (obj->layer->evas)) pdata->evas_pdata->seat->mouse_grabbed -= pdata->mouse_grabbed; @@ -151,11 +135,12 @@ _evas_object_pointer_grab_del(Evas_Object_Protected_Data *obj, if (obj->proxy->is_proxy && obj->proxy->src_events) _evas_object_proxy_grab_del(obj, pdata); } - efl_event_callback_del(pdata->evas_pdata->pointer, EFL_EVENT_DEL, - _evas_device_del_cb, obj->object); - EINA_COW_WRITE_BEGIN(evas_object_events_cow, obj->events, Evas_Object_Events_Data, events) - events->pointer_grabs = eina_inlist_remove(events->pointer_grabs, EINA_INLIST_GET(pdata)); - EINA_COW_WRITE_END(evas_object_events_cow, obj->events, events); + if (obj->events->pointer_grabs) + { + EINA_COW_WRITE_BEGIN(evas_object_events_cow, obj->events, Evas_Object_Events_Data, events) + events->pointer_grabs = eina_inlist_remove(events->pointer_grabs, EINA_INLIST_GET(pdata)); + EINA_COW_WRITE_END(evas_object_events_cow, obj->events, events); + } free(pdata); } @@ -170,14 +155,13 @@ _evas_object_pointer_data_add(Evas_Pointer_Data *evas_pdata, EINA_SAFETY_ON_NULL_RETURN_VAL(pdata, NULL); pdata->pointer_mode = EVAS_OBJECT_POINTER_MODE_AUTOGRAB; pdata->evas_pdata = evas_pdata; + pdata->obj = obj; EINA_COW_WRITE_BEGIN(evas_object_events_cow, obj->events, Evas_Object_Events_Data, events) events->pointer_grabs = eina_inlist_append(events->pointer_grabs, EINA_INLIST_GET(pdata)); EINA_COW_WRITE_END(evas_object_events_cow, obj->events, events); - efl_event_callback_priority_add(evas_pdata->pointer, EFL_EVENT_DEL, - EFL_CALLBACK_PRIORITY_BEFORE, - _evas_device_del_cb, obj->object); + efl_input_device_grab_register(evas_pdata->pointer, obj->object, pdata); return pdata; } @@ -187,7 +171,7 @@ _evas_object_pointer_data_get(Evas_Pointer_Data *evas_pdata, { Evas_Object_Pointer_Data *pdata; - pdata = _evas_object_pointer_data_find(obj, evas_pdata->pointer); + pdata = evas_object_pointer_data_find(obj, evas_pdata->pointer); //The pointer does not exist yet - create one. if (!pdata) @@ -1068,29 +1052,39 @@ _efl_canvas_object_efl_object_invalidate(Eo *eo_obj, Evas_Object_Protected_Data evas_object_hide(eo_obj); if (obj->events) - EINA_COW_WRITE_BEGIN(evas_object_events_cow, obj->events, Evas_Object_Events_Data, events) - { - Evas_Public_Data *edata = NULL; + { + Eina_Inlist *pointer_grabs; - if (!efl_invalidated_get(evas_object_evas_get(eo_obj))) - edata = efl_data_scope_get(evas_object_evas_get(eo_obj), EVAS_CANVAS_CLASS); + EINA_COW_WRITE_BEGIN(evas_object_events_cow, obj->events, Evas_Object_Events_Data, events) + { + Evas_Public_Data *edata = NULL; - EINA_LIST_FREE (events->focused_by_seats, dev) - { - event_id = _evas_event_counter; - efl_event_callback_del(dev, EFL_EVENT_INVALIDATE, - _evas_focus_device_invalidate_cb, obj); - if (edata) eina_hash_del_by_key(edata->focused_objects, &dev); - _evas_focus_dispatch_event(obj, dev, EINA_FALSE); - if ((obj->layer) && (obj->layer->evas)) - _evas_post_event_callback_call(obj->layer->evas->evas, obj->layer->evas, event_id); - } - EINA_INLIST_FREE(events->pointer_grabs, pdata) - _evas_object_pointer_grab_del(obj, pdata); - EINA_LIST_FREE(events->events_whitelist, dev) - efl_event_callback_del(dev, EFL_EVENT_DEL, _whitelist_events_device_remove_cb, obj); - } - EINA_COW_WRITE_END(evas_object_events_cow, obj->events, events); + if (!efl_invalidated_get(evas_object_evas_get(eo_obj))) + edata = efl_data_scope_get(evas_object_evas_get(eo_obj), EVAS_CANVAS_CLASS); + + EINA_LIST_FREE (events->focused_by_seats, dev) + { + event_id = _evas_event_counter; + efl_event_callback_del(dev, EFL_EVENT_INVALIDATE, + _evas_focus_device_invalidate_cb, obj); + if (edata) eina_hash_del_by_key(edata->focused_objects, &dev); + _evas_focus_dispatch_event(obj, dev, EINA_FALSE); + if ((obj->layer) && (obj->layer->evas)) + _evas_post_event_callback_call(obj->layer->evas->evas, obj->layer->evas, event_id); + } + pointer_grabs = events->pointer_grabs; + events->pointer_grabs = NULL; + EINA_LIST_FREE(events->events_whitelist, dev) + efl_event_callback_del(dev, EFL_EVENT_DEL, _whitelist_events_device_remove_cb, obj); + } + EINA_COW_WRITE_END(evas_object_events_cow, obj->events, events); + + EINA_INLIST_FREE(pointer_grabs, pdata) + { + pointer_grabs = eina_inlist_remove(pointer_grabs, EINA_INLIST_GET(pdata)); + efl_input_device_grab_unregister(pdata->evas_pdata->pointer, eo_obj, pdata); + } + } event_id = _evas_object_event_new(); evas_object_event_callback_call(eo_obj, obj, EVAS_CALLBACK_DEL, NULL, event_id, NULL); diff --git a/src/lib/evas/include/evas_private.h b/src/lib/evas/include/evas_private.h index 6906195db9..2081c3dc85 100644 --- a/src/lib/evas/include/evas_private.h +++ b/src/lib/evas/include/evas_private.h @@ -77,6 +77,7 @@ typedef struct _Evas_Format Evas_Format; typedef struct _Evas_Map_Point Evas_Map_Point; typedef struct _Evas_Smart_Cb_Description_Array Evas_Smart_Cb_Description_Array; typedef struct _Evas_Smart_Interfaces_Array Evas_Smart_Interfaces_Array; +typedef enum _Evas_Object_Intercept_Cb_Type Evas_Object_Intercept_Cb_Type; typedef struct _Evas_Post_Callback Evas_Post_Callback; typedef struct _Evas_Coord_Touch_Point Evas_Coord_Touch_Point; typedef struct _Evas_Object_Proxy_Data Evas_Object_Proxy_Data; @@ -1095,6 +1096,7 @@ struct _Evas_Object_Protected_State struct _Evas_Object_Pointer_Data { EINA_INLIST; + Evas_Object_Protected_Data *obj; Evas_Pointer_Data *evas_pdata; Evas_Object_Pointer_Mode pointer_mode; int mouse_grabbed; @@ -1679,6 +1681,10 @@ void evas_object_inform_call_image_preloaded(Evas_Object *obj); void evas_object_inform_call_image_unloaded(Evas_Object *obj); void evas_object_inform_call_image_resize(Evas_Object *obj); void evas_object_intercept_cleanup(Evas_Object *obj); +Evas_Object_Pointer_Data *evas_object_pointer_data_find(Evas_Object_Protected_Data *obj, + Efl_Input_Device *pointer); +void evas_object_pointer_grab_del(Evas_Object_Protected_Data *obj, + Evas_Object_Pointer_Data *pdata); void evas_object_grabs_cleanup(Evas_Object *obj, Evas_Object_Protected_Data *pd); void evas_key_grab_free(Evas_Object *obj, Evas_Object_Protected_Data *pd, const char *keyname, Evas_Modifier_Mask modifiers, Evas_Modifier_Mask not_modifiers); void evas_object_smart_member_cache_invalidate(Evas_Object *obj, Eina_Bool pass_events, Eina_Bool freeze_events, Eina_Bool source_invisible);