evas vector: make it stable caching logic.

We need a more precise caching mechanism to save memory.
Current root node(key) is limited for caching buffers,
when to share by the multiple animated instances.

This patch is a step for further optmization work,
at the moment we disable the caching buffers for the animated instances.
This commit is contained in:
Hermet Park 2019-11-28 13:38:32 +09:00
parent f6caca1d70
commit 408bfb3e35
3 changed files with 27 additions and 85 deletions

View File

@ -565,6 +565,7 @@ _cache_vg_entry_render(Evas_Object_Protected_Data *obj,
Vg_Cache_Entry *vg_entry = pd->vg_entry; Vg_Cache_Entry *vg_entry = pd->vg_entry;
Efl_VG *root; Efl_VG *root;
Eina_Position2D offset = {0, 0}; //Offset after keeping aspect ratio. Eina_Position2D offset = {0, 0}; //Offset after keeping aspect ratio.
Eina_Bool drop_cache = EINA_FALSE;
void *buffer = NULL; void *buffer = NULL;
evas_cache_vg_entry_value_provider_update(pd->vg_entry, efl_key_data_get(obj->object, "_vg_value_providers")); evas_cache_vg_entry_value_provider_update(pd->vg_entry, efl_key_data_get(obj->object, "_vg_value_providers"));
@ -601,10 +602,7 @@ _cache_vg_entry_render(Evas_Object_Protected_Data *obj,
//Size is changed, cached data is invalid. //Size is changed, cached data is invalid.
if ((size.w != vg_entry->w) || (size.h != vg_entry->h)) if ((size.w != vg_entry->w) || (size.h != vg_entry->h))
{ {
//if the size doesn't match, drop previous cache surfaces. drop_cache = EINA_TRUE;
ENFN->ector_surface_cache_drop(engine, (void *) vg_entry->root[1]);
ENFN->ector_surface_cache_drop(engine, (void *) vg_entry->root[2]);
vg_entry = evas_cache_vg_entry_resize(vg_entry, size.w, size.h); vg_entry = evas_cache_vg_entry_resize(vg_entry, size.w, size.h);
evas_cache_vg_entry_del(pd->vg_entry); evas_cache_vg_entry_del(pd->vg_entry);
pd->vg_entry = vg_entry; pd->vg_entry = vg_entry;
@ -624,12 +622,17 @@ _cache_vg_entry_render(Evas_Object_Protected_Data *obj,
if (cacheable) if (cacheable)
{ {
//if the size doesn't match, drop previous cache surface.
if (drop_cache)
ENFN->ector_surface_cache_drop(engine, (void *) root);
//Cache Hit! //Cache Hit!
buffer = ENFN->ector_surface_cache_get(engine, (void *) root); else
buffer = ENFN->ector_surface_cache_get(engine, (void *) root);
} }
if (!buffer) if (!buffer)
buffer = _render_to_buffer(obj, pd, engine, root, w, h, NULL, do_async, cacheable); buffer = _render_to_buffer(obj, pd, engine, root, w, h, NULL,
do_async, cacheable);
else else
//cache reference was increased when we get the cache. //cache reference was increased when we get the cache.
ENFN->ector_surface_cache_drop(engine, (void *) root); ENFN->ector_surface_cache_drop(engine, (void *) root);
@ -712,12 +715,8 @@ _efl_canvas_vg_object_render(Evas_Object *eo_obj EINA_UNUSED,
//Cache surface? //Cache surface?
Eina_Bool cacheable = EINA_FALSE; Eina_Bool cacheable = EINA_FALSE;
/* Try caching buffer only for first and last frames /* Try caching buffer only for static images. */
because it's an overhead task if it caches all frame images. if (evas_cache_vg_anim_frame_count_get(pd->vg_entry) == 0)
We assume the first and last frame images are the most resusable
in generic scenarios. */
if (pd->frame_idx == 0 ||
(pd->frame_idx == (int) (evas_cache_vg_anim_frame_count_get(pd->vg_entry) - 1)))
cacheable = EINA_TRUE; cacheable = EINA_TRUE;
if (pd->vg_entry) if (pd->vg_entry)

View File

@ -26,7 +26,7 @@ typedef struct _Vg_Cache_Entry
Eina_Stringshare *key; Eina_Stringshare *key;
int w; int w;
int h; int h;
Efl_VG *root[3]; //0: default, 1: start frame, 2: end frame Efl_VG *root;
int ref; int ref;
Vg_File_Data *vfd; Vg_File_Data *vfd;
} Vg_Cache_Entry; } Vg_Cache_Entry;

View File

@ -83,9 +83,7 @@ _vg_load_from_file(const Eina_File *file, const char *key)
if (em) if (em)
{ {
loader = em->functions; loader = em->functions;
{ vfd = loader->file_open((Eina_File *) file, key, &error);
vfd = loader->file_open((Eina_File *) file, key, &error);
}
if (vfd) if (vfd)
{ {
vfd->loader = loader; vfd->loader = loader;
@ -167,9 +165,7 @@ _evas_cache_vg_entry_free_cb(void *data)
eina_stringshare_del(vg_entry->key); eina_stringshare_del(vg_entry->key);
free(vg_entry->hash_key); free(vg_entry->hash_key);
efl_unref(vg_entry->root[0]); efl_unref(vg_entry->root);
efl_unref(vg_entry->root[1]);
efl_unref(vg_entry->root[2]);
free(vg_entry); free(vg_entry);
} }
@ -198,42 +194,8 @@ _vg_file_save(Vg_File_Data *vfd, const char *file, const char *key, const Efl_Fi
return EINA_TRUE; return EINA_TRUE;
} }
static Efl_VG* static void
_cached_root_get(Vg_Cache_Entry *vg_entry, unsigned int frame_num) _root_update(Vg_Cache_Entry *vg_entry)
{
Vg_File_Data *vfd = vg_entry->vfd;
//Case 1: Animatable
if (vfd->anim_data)
{
//Start frame
if (vg_entry->root[1] && frame_num == 0)
{
return vg_entry->root[1];
}
//End frame
else if (vg_entry->root[2] && (frame_num == (vfd->anim_data->frame_cnt - 1)))
{
return vg_entry->root[2];
}
//Current frame
else if (vg_entry->root[0] && (frame_num == (vfd->anim_data->frame_num)))
{
return vg_entry->root[0];
}
}
//Case 2: Static
else
{
if (vg_entry->root[0])
return vg_entry->root[0];
}
return NULL;
}
static Efl_VG *
_caching_root_update(Vg_Cache_Entry *vg_entry)
{ {
Vg_File_Data *vfd = vg_entry->vfd; Vg_File_Data *vfd = vg_entry->vfd;
@ -246,33 +208,14 @@ _caching_root_update(Vg_Cache_Entry *vg_entry)
/* TODO: Yet trivial but still we may have a better solution to /* TODO: Yet trivial but still we may have a better solution to
avoid this unnecessary copy. If the ector surface key is not avoid this unnecessary copy. If the ector surface key is not
to this root pointer. */ to this root pointer. */
vg_entry->root[0] = efl_duplicate(vfd->root); vg_entry->root = efl_duplicate(vfd->root);
} }
else //Shareable??
else if (vg_entry->root != vfd->root)
{ {
if (vg_entry->root[0]) efl_unref(vg_entry->root[0]); if (vg_entry->root) efl_unref(vg_entry->root);
vg_entry->root[0] = efl_duplicate(vfd->root); vg_entry->root = efl_ref(vfd->root);
//Animatable?
if (vfd->anim_data)
{
//Start frame
if (vfd->anim_data->frame_num == 0)
{
if (vg_entry->root[1]) efl_unref(vg_entry->root[1]);
vg_entry->root[1] = efl_duplicate(vfd->root);
return vg_entry->root[1];
}
//End frame
else if (vfd->anim_data->frame_num == (vfd->anim_data->frame_cnt - 1))
{
if (vg_entry->root[2]) efl_unref(vg_entry->root[2]);
vg_entry->root[2] = efl_duplicate(vfd->root);
return vg_entry->root[2];
}
}
} }
return vg_entry->root[0];
} }
static void static void
@ -374,7 +317,6 @@ evas_cache_vg_entry_create(Evas *evas,
if (!vg_cache) return NULL; if (!vg_cache) return NULL;
//TODO: zero-sized entry is useless. how to skip it? //TODO: zero-sized entry is useless. how to skip it?
//
hash_key = eina_strbuf_new(); hash_key = eina_strbuf_new();
eina_strbuf_append_printf(hash_key, "%p/%p/%s/%d/%d/%p", evas, file, key, w, h, vp_list); eina_strbuf_append_printf(hash_key, "%p/%p/%s/%d/%d/%p", evas, file, key, w, h, vp_list);
vg_entry = eina_hash_find(vg_cache->vg_entry_hash, eina_strbuf_string_get(hash_key)); vg_entry = eina_hash_find(vg_cache->vg_entry_hash, eina_strbuf_string_get(hash_key));
@ -488,8 +430,9 @@ evas_cache_vg_tree_get(Vg_Cache_Entry *vg_entry, unsigned int frame_num)
Vg_File_Data *vfd = vg_entry->vfd; Vg_File_Data *vfd = vg_entry->vfd;
if (!vfd) return NULL; if (!vfd) return NULL;
Efl_VG *root = _cached_root_get(vg_entry, frame_num); //No need to update.
if (root) return root; if (!vfd->anim_data && vg_entry->root)
return vg_entry->root;
if (!vfd->static_viewbox) if (!vfd->static_viewbox)
{ {
@ -501,11 +444,11 @@ evas_cache_vg_tree_get(Vg_Cache_Entry *vg_entry, unsigned int frame_num)
if (!vfd->loader->file_data(vfd)) return NULL; if (!vfd->loader->file_data(vfd)) return NULL;
root = _caching_root_update(vg_entry); _root_update(vg_entry);
_local_transform(root, vg_entry->w, vg_entry->h, vfd); _local_transform(vg_entry->root, vg_entry->w, vg_entry->h, vfd);
return root; return vg_entry->root;
} }
void void