forked from enlightenment/efl
efl: make Efl.Ui.Factory.release work in batches.
This will enable better strategy in scheduling removal of object from the cache instead of doing the throttling in the View as there is a better understanding of the different layer the items are going to go through and where they will consume time. Reviewed-by: Marcel Hollerbach <mail@marcel-hollerbach.de> Differential Revision: https://phab.enlightenment.org/D9955
This commit is contained in:
parent
0a99fb87bb
commit
5493cc5396
|
@ -29,7 +29,7 @@ interface @beta Efl.Ui.Factory extends Efl.Ui.Property_Bind, Efl.Ui.Factory_Bind
|
|||
release {
|
||||
[[Release a UI object and disconnect from models.]]
|
||||
params {
|
||||
ui_view: Efl.Gfx.Entity; [[Object to remove.]]
|
||||
ui_views: iterator<Efl.Gfx.Entity> @move; [[Object to remove.]]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ struct _Efl_Ui_Caching_Factory_Data
|
|||
// end of the list objects are added and removed.
|
||||
Eina_List *cache;
|
||||
Eina_Hash *lookup;
|
||||
Eina_Future *flush;
|
||||
|
||||
struct {
|
||||
unsigned int memory;
|
||||
|
@ -57,15 +58,29 @@ _efl_ui_caching_factory_remove(Efl_Ui_Caching_Factory_Data *pd, Eina_List *l, Ef
|
|||
|
||||
static void
|
||||
_efl_ui_caching_factory_item_del(Eo *obj, Efl_Ui_Caching_Factory_Data *pd,
|
||||
Efl_Gfx_Entity *entity)
|
||||
Eina_Iterator *entities)
|
||||
{
|
||||
if (pd->klass) efl_del(entity);
|
||||
else efl_ui_factory_release(efl_super(obj, EFL_UI_CACHING_FACTORY_CLASS), entity);
|
||||
if (!pd->klass)
|
||||
{
|
||||
efl_ui_factory_release(efl_super(obj, EFL_UI_CACHING_FACTORY_CLASS), entities);
|
||||
}
|
||||
else
|
||||
{
|
||||
Efl_Gfx_Entity *entity;
|
||||
|
||||
EINA_ITERATOR_FOREACH(entities, entity)
|
||||
efl_del(entity);
|
||||
eina_iterator_free(entities);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_efl_ui_caching_factory_flush(Eo *obj, Efl_Ui_Caching_Factory_Data *pd)
|
||||
{
|
||||
Eina_Array scheduled;
|
||||
|
||||
eina_array_step_set(&scheduled, sizeof (Eina_Array), 8);
|
||||
|
||||
while (pd->limit.items != 0 &&
|
||||
pd->current.items > pd->limit.items)
|
||||
{
|
||||
|
@ -75,7 +90,8 @@ _efl_ui_caching_factory_flush(Eo *obj, Efl_Ui_Caching_Factory_Data *pd)
|
|||
|
||||
_efl_ui_caching_factory_remove(pd, eina_list_last(pd->cache), entity);
|
||||
if (pd->lookup) eina_hash_del(pd->lookup, efl_ui_widget_style_get(entity), entity);
|
||||
_efl_ui_caching_factory_item_del(obj, pd, entity);
|
||||
|
||||
eina_array_push(&scheduled, entity);
|
||||
}
|
||||
|
||||
while (pd->limit.memory != 0 &&
|
||||
|
@ -87,8 +103,13 @@ _efl_ui_caching_factory_flush(Eo *obj, Efl_Ui_Caching_Factory_Data *pd)
|
|||
|
||||
_efl_ui_caching_factory_remove(pd, eina_list_last(pd->cache), entity);
|
||||
if (pd->lookup) eina_hash_del(pd->lookup, efl_ui_widget_style_get(entity), entity);
|
||||
_efl_ui_caching_factory_item_del(obj, pd, entity);
|
||||
|
||||
eina_array_push(&scheduled, entity);
|
||||
}
|
||||
|
||||
// We could improve this by doing some limited batch to reduce potential spike usage
|
||||
_efl_ui_caching_factory_item_del(obj, pd, eina_array_iterator_new(&scheduled));
|
||||
eina_array_flush(&scheduled);
|
||||
}
|
||||
|
||||
static Eina_Value
|
||||
|
@ -343,38 +364,67 @@ _efl_ui_caching_factory_items_limit_get(const Eo *obj EINA_UNUSED,
|
|||
return pd->limit.items;
|
||||
}
|
||||
|
||||
static void
|
||||
_efl_ui_caching_factory_efl_ui_factory_release(Eo *obj,
|
||||
Efl_Ui_Caching_Factory_Data *pd,
|
||||
Efl_Gfx_Entity *ui_view)
|
||||
static Eina_Value
|
||||
_schedule_cache_flush(Eo *obj, void *data, const Eina_Value v)
|
||||
{
|
||||
// Are we invalidated ?
|
||||
if (pd->invalidated)
|
||||
{
|
||||
_efl_ui_caching_factory_item_del(obj, pd, ui_view);
|
||||
return;
|
||||
}
|
||||
|
||||
// Change parent, disconnect the object and make it invisible
|
||||
efl_gfx_entity_visible_set(ui_view, EINA_FALSE);
|
||||
efl_event_callback_call(obj, EFL_UI_FACTORY_EVENT_ITEM_RELEASING, ui_view);
|
||||
|
||||
// Add to the cache
|
||||
pd->cache = eina_list_prepend(pd->cache, ui_view);
|
||||
pd->current.items++;
|
||||
pd->current.memory += efl_class_memory_size_get(ui_view);
|
||||
if (efl_isa(ui_view, EFL_CACHED_ITEM_INTERFACE))
|
||||
pd->current.memory += efl_cached_item_memory_size_get(ui_view);
|
||||
|
||||
// Fill lookup
|
||||
if (!pd->klass && efl_ui_widget_style_get(ui_view))
|
||||
{
|
||||
if (!pd->lookup) pd->lookup = eina_hash_string_djb2_new(NULL);
|
||||
eina_hash_direct_add(pd->lookup, efl_ui_widget_style_get(ui_view), ui_view);
|
||||
}
|
||||
Efl_Ui_Caching_Factory_Data *pd = data;
|
||||
|
||||
// And check if the cache need some triming
|
||||
_efl_ui_caching_factory_flush(obj, pd);
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
static void
|
||||
_schedule_done(Eo *o EINA_UNUSED, void *data, const Eina_Future *dead_future EINA_UNUSED)
|
||||
{
|
||||
Efl_Ui_Caching_Factory_Data *pd = data;
|
||||
|
||||
pd->flush = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
_efl_ui_caching_factory_efl_ui_factory_release(Eo *obj,
|
||||
Efl_Ui_Caching_Factory_Data *pd,
|
||||
Eina_Iterator *ui_views)
|
||||
{
|
||||
Efl_Gfx_Entity *ui_view;
|
||||
|
||||
// Are we invalidated ?
|
||||
if (pd->invalidated)
|
||||
{
|
||||
_efl_ui_caching_factory_item_del(obj, pd, ui_views);
|
||||
return;
|
||||
}
|
||||
|
||||
EINA_ITERATOR_FOREACH(ui_views, ui_view)
|
||||
{
|
||||
// Change parent, disconnect the object and make it invisible
|
||||
efl_gfx_entity_visible_set(ui_view, EINA_FALSE);
|
||||
efl_event_callback_call(obj, EFL_UI_FACTORY_EVENT_ITEM_RELEASING, ui_view);
|
||||
|
||||
// Add to the cache
|
||||
pd->cache = eina_list_prepend(pd->cache, ui_view);
|
||||
pd->current.items++;
|
||||
pd->current.memory += efl_class_memory_size_get(ui_view);
|
||||
if (efl_isa(ui_view, EFL_CACHED_ITEM_INTERFACE))
|
||||
pd->current.memory += efl_cached_item_memory_size_get(ui_view);
|
||||
|
||||
// Fill lookup
|
||||
if (!pd->klass && efl_ui_widget_style_get(ui_view))
|
||||
{
|
||||
if (!pd->lookup) pd->lookup = eina_hash_string_djb2_new(NULL);
|
||||
eina_hash_direct_add(pd->lookup, efl_ui_widget_style_get(ui_view), ui_view);
|
||||
}
|
||||
}
|
||||
eina_iterator_free(ui_views);
|
||||
|
||||
// Schedule a cache flush if necessary
|
||||
if (!pd->flush)
|
||||
pd->flush = efl_future_then(obj, efl_loop_job(efl_loop_get(obj)),
|
||||
.success = _schedule_cache_flush,
|
||||
.free = _schedule_done,
|
||||
.data = pd);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
@ -2193,14 +2193,14 @@ _content_created(Eo *obj, void *data, const Eina_Value value)
|
|||
{
|
||||
Efl_Ui_Layout_Factory_Request *request = data;
|
||||
Efl_Gfx_Entity *content = NULL;
|
||||
Efl_Gfx_Entity *old_content;
|
||||
Efl_Gfx_Entity *old_content[1];
|
||||
int len, i;
|
||||
|
||||
EINA_VALUE_ARRAY_FOREACH(&value, len, i, content)
|
||||
{
|
||||
// Recycle old content
|
||||
old_content = efl_content_get(efl_part(obj, request->key));
|
||||
if (old_content) efl_ui_factory_release(request->factory, old_content);
|
||||
old_content[0] = efl_content_get(efl_part(obj, request->key));
|
||||
if (old_content[0]) efl_ui_factory_release(request->factory, EINA_C_ARRAY_ITERATOR_NEW(old_content));
|
||||
|
||||
// Set new content
|
||||
efl_content_set(efl_part(obj, request->key), content);
|
||||
|
@ -2364,7 +2364,7 @@ _efl_ui_layout_base_model_register(Eo *obj, Efl_Ui_Layout_Data *pd,
|
|||
EINA_ITERATOR_FOREACH(it, tuple)
|
||||
{
|
||||
Efl_Ui_Layout_Factory_Tracking *factory;
|
||||
Efl_Gfx_Entity *content;
|
||||
Efl_Gfx_Entity *content[1];
|
||||
|
||||
key = tuple->key;
|
||||
factory = tuple->data;
|
||||
|
@ -2373,11 +2373,11 @@ _efl_ui_layout_base_model_register(Eo *obj, Efl_Ui_Layout_Data *pd,
|
|||
if (factory->in_flight) eina_future_cancel(factory->in_flight);
|
||||
|
||||
// Cleanup content
|
||||
content = efl_content_get(efl_part(obj, key));
|
||||
content[0] = efl_content_get(efl_part(obj, key));
|
||||
efl_content_unset(efl_part(obj, key));
|
||||
|
||||
// And recycle it
|
||||
if (content) efl_ui_factory_release(factory->factory, content);
|
||||
if (content[0]) efl_ui_factory_release(factory->factory, EINA_C_ARRAY_ITERATOR_NEW(content));
|
||||
}
|
||||
eina_iterator_free(it);
|
||||
|
||||
|
@ -2500,12 +2500,12 @@ _efl_ui_layout_base_efl_ui_factory_bind_factory_bind(Eo *obj EINA_UNUSED, Efl_Ui
|
|||
tracking = eina_hash_find(pd->connect.factories, ss_key);
|
||||
if (tracking)
|
||||
{
|
||||
Efl_Gfx_Entity *old;
|
||||
Efl_Gfx_Entity *old[1];
|
||||
|
||||
// Unset and recycle
|
||||
old = efl_content_get(efl_part(obj, ss_key));
|
||||
old[0] = efl_content_get(efl_part(obj, ss_key));
|
||||
efl_content_unset(efl_part(obj, ss_key));
|
||||
if (old) efl_ui_factory_release(tracking->factory, old);
|
||||
if (old[0]) efl_ui_factory_release(tracking->factory, EINA_C_ARRAY_ITERATOR_NEW(old));
|
||||
|
||||
// Stop in flight request
|
||||
if (tracking->in_flight) eina_future_cancel(tracking->in_flight);
|
||||
|
|
|
@ -973,6 +973,7 @@ EOLIAN static void
|
|||
_efl_ui_list_view_efl_ui_list_view_model_unrealize(Eo *obj, Efl_Ui_List_View_Data *pd, Efl_Ui_List_View_Layout_Item *item)
|
||||
{
|
||||
Efl_Ui_List_View_Item_Event evt;
|
||||
Efl_Gfx_Entity *entities[1];
|
||||
EINA_SAFETY_ON_NULL_RETURN(item);
|
||||
|
||||
if (!item->layout)
|
||||
|
@ -1001,7 +1002,8 @@ _efl_ui_list_view_efl_ui_list_view_model_unrealize(Eo *obj, Efl_Ui_List_View_Dat
|
|||
efl_event_callback_call(obj, EFL_UI_LIST_VIEW_EVENT_ITEM_UNREALIZED, &evt);
|
||||
|
||||
efl_canvas_group_member_remove(obj, pd->pan_obj);
|
||||
efl_ui_factory_release(pd->factory, item->layout);
|
||||
entities[0] = item->layout;
|
||||
efl_ui_factory_release(pd->factory, EINA_C_ARRAY_ITERATOR_NEW(entities));
|
||||
item->layout = NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -326,13 +326,19 @@ alloc_array_error:
|
|||
static void
|
||||
_efl_ui_widget_factory_efl_ui_factory_release(Eo *obj,
|
||||
Efl_Ui_Widget_Factory_Data *pd EINA_UNUSED,
|
||||
Efl_Gfx_Entity *ui_view)
|
||||
Eina_Iterator *ui_views)
|
||||
{
|
||||
// There might be multiple call to releasing on the same object as every factory in the
|
||||
// inheritance chain can decide to keep it for a time
|
||||
efl_event_callback_call(obj, EFL_UI_FACTORY_EVENT_ITEM_RELEASING, ui_view);
|
||||
// We do not cache or track this item, just get rid of them asap
|
||||
efl_del(ui_view);
|
||||
Efl_Gfx_Entity *ui_view;
|
||||
|
||||
EINA_ITERATOR_FOREACH(ui_views, ui_view)
|
||||
{
|
||||
// There might be multiple call to releasing on the same object as every factory in the
|
||||
// inheritance chain can decide to keep it for a time
|
||||
efl_event_callback_call(obj, EFL_UI_FACTORY_EVENT_ITEM_RELEASING, ui_view);
|
||||
// We do not cache or track this item, just get rid of them asap
|
||||
efl_del(ui_view);
|
||||
}
|
||||
eina_iterator_free(ui_views);
|
||||
}
|
||||
|
||||
Eina_Stringshare *_property_style_ss = NULL;
|
||||
|
|
Loading…
Reference in New Issue