From: Hermet Park Date: Fri, 13 Dec 2019 08:22:54 +0000 (+0900) Subject: evas vg: revise buffer caching method. X-Git-Tag: accepted/tizen/unified/20191216.222241~24 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=d35c567de40b535920dae08cfe345bc28a1f7dd0;p=platform%2Fupstream%2Fefl.git evas vg: revise buffer caching method. for better precise buffer cache key, We make a unique key name combining root node + size + frame index. Now, we can reuse the root node for animation and caching buffers. Change-Id: I4370b8b234dd47279370edbb557194b8f6d925c3 --- diff --git a/src/lib/evas/canvas/efl_canvas_vg_object.c b/src/lib/evas/canvas/efl_canvas_vg_object.c index 740cfac..83a59bd 100644 --- a/src/lib/evas/canvas/efl_canvas_vg_object.c +++ b/src/lib/evas/canvas/efl_canvas_vg_object.c @@ -144,6 +144,8 @@ _efl_canvas_vg_object_root_node_set(Eo *eo_obj, Efl_Canvas_Vg_Object_Data *pd, E // detach/free the old root_node if (pd->user_entry && pd->user_entry->root) { + // drop any surface cache attached to it. + ENFN->ector_surface_cache_drop(_evas_engine_context(obj->layer->evas), pd->user_entry->root); efl_canvas_vg_node_vg_obj_set(pd->user_entry->root, NULL, NULL); efl_replace(&pd->user_entry->root, NULL); } @@ -166,8 +168,6 @@ _efl_canvas_vg_object_root_node_set(Eo *eo_obj, Efl_Canvas_Vg_Object_Data *pd, E } else if (pd->user_entry) { - // drop any surface cache attached to it. - ENFN->ector_surface_cache_drop(_evas_engine_context(obj->layer->evas), pd->user_entry->root); free(pd->user_entry); pd->user_entry = NULL; } @@ -345,7 +345,6 @@ _efl_canvas_vg_object_efl_object_invalidate(Eo *eo_obj, Efl_Canvas_Vg_Object_Dat if (pd->user_entry) { Vg_User_Entry *user_entry = pd->user_entry; - ENFN->ector_surface_cache_drop(ENC, user_entry->root); free(pd->user_entry); } @@ -492,8 +491,8 @@ _evas_vg_render(Evas_Object_Protected_Data *obj, Efl_Canvas_Vg_Object_Data *pd, //renders a vg_tree to an offscreen buffer and push it to the cache. static void * _render_to_buffer(Evas_Object_Protected_Data *obj, Efl_Canvas_Vg_Object_Data *pd, - void *engine, Efl_VG *root, int w, int h, void *buffer, - Eina_Bool do_async, Eina_Bool cacheable) + void *engine, Efl_VG *root, int w, int h, void *buffer, void *ckey, + Eina_Bool do_async) { Ector_Surface *ector; RGBA_Draw_Context *context; @@ -534,11 +533,8 @@ _render_to_buffer(Evas_Object_Protected_Data *obj, Efl_Canvas_Vg_Object_Data *pd ENFN->ector_end(engine, buffer, context, ector, do_async); evas_common_draw_context_free(context); - if (buffer_created && cacheable) - { - //Use root as a cache key. - ENFN->ector_surface_cache_set(engine, root, buffer); - } + if (buffer_created && ckey) + ENFN->ector_surface_cache_set(engine, ckey, buffer); return buffer; } @@ -579,8 +575,8 @@ _cache_vg_entry_render(Evas_Object_Protected_Data *obj, Vg_Cache_Entry *vg_entry = pd->vg_entry; Efl_VG *root; Eina_Position2D offset = {0, 0}; //Offset after keeping aspect ratio. - Eina_Bool drop_cache = EINA_FALSE; void *buffer = NULL; + void *key = NULL; evas_cache_vg_entry_value_provider_update(pd->vg_entry, efl_key_data_get(obj->object, "_vg_value_providers")); @@ -616,7 +612,23 @@ _cache_vg_entry_render(Evas_Object_Protected_Data *obj, //Size is changed, cached data is invalid. if ((size.w != vg_entry->w) || (size.h != vg_entry->h)) { - drop_cache = EINA_TRUE; +//Not necessary, but this might be helpful for precise caching. +#if 0 + if (cacheable) + { + //if the size doesn't match, drop previous cache surface. + key = evas_cache_vg_surface_key_get(pd->vg_entry->root, vg_entry->w, vg_entry->h, 0); + if (key) ENFN->ector_surface_cache_drop(engine, key); + + //Animatable... Try to drop the last frame image. + int last_frame = (int) (evas_cache_vg_anim_frame_count_get(pd->vg_entry) - 1); + if (last_frame > 0) + { + key = evas_cache_vg_surface_key_get(pd->vg_entry->root, vg_entry->w, vg_entry->h, last_frame); + if (key) ENFN->ector_surface_cache_drop(engine, key); + } + } +#endif vg_entry = evas_cache_vg_entry_resize(vg_entry, size.w, size.h); evas_cache_vg_entry_del(pd->vg_entry); pd->vg_entry = vg_entry; @@ -629,27 +641,25 @@ _cache_vg_entry_render(Evas_Object_Protected_Data *obj, if (offset.y > 0) offset.y /= 2; w = size.w; h = size.h; - } root = evas_cache_vg_tree_get(vg_entry, pd->frame_idx); if (!root) return; 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! - else - buffer = ENFN->ector_surface_cache_get(engine, (void *) root); + key = evas_cache_vg_surface_key_get(root, w, h, pd->frame_idx); + if (key) buffer = ENFN->ector_surface_cache_get(engine, key); } 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, key, do_async); + } else - //cache reference was increased when we get the cache. - ENFN->ector_surface_cache_drop(engine, (void *) root); + { + //cache reference was increased when we get the cache. + if (key) ENFN->ector_surface_cache_drop(engine, key); + } _render_buffer_to_screen(obj, engine, output, context, surface, @@ -662,8 +672,7 @@ static void _user_vg_entry_render(Evas_Object_Protected_Data *obj, Efl_Canvas_Vg_Object_Data *pd, void *engine, void *output, void *context, void *surface, - int x, int y, int w, int h, Eina_Bool do_async, - Eina_Bool cacheable) + int x, int y, int w, int h, Eina_Bool do_async) { Vg_User_Entry *user_entry = pd->user_entry; @@ -679,14 +688,13 @@ _user_vg_entry_render(Evas_Object_Protected_Data *obj, //if the buffer is not created yet void *buffer = NULL; - if (cacheable) buffer = ENFN->ector_surface_cache_get(engine, user_entry->root); if (!buffer) { // render to the buffer buffer = _render_to_buffer(obj, pd, engine, user_entry->root, - w, h, buffer, do_async, cacheable); + w, h, buffer, user_entry->root, do_async); } else { @@ -694,8 +702,8 @@ _user_vg_entry_render(Evas_Object_Protected_Data *obj, if (pd->changed) buffer = _render_to_buffer(obj, pd, engine, user_entry->root, - w, h, buffer, - do_async, EINA_FALSE); + w, h, buffer, NULL, + do_async); //cache reference was increased when we get the cache. ENFN->ector_surface_cache_drop(engine, user_entry->root); } @@ -704,7 +712,7 @@ _user_vg_entry_render(Evas_Object_Protected_Data *obj, engine, output, context, surface, buffer, x, y, w, h, - do_async, cacheable); + do_async, EINA_TRUE); } static void @@ -729,8 +737,12 @@ _efl_canvas_vg_object_render(Evas_Object *eo_obj EINA_UNUSED, //Cache surface? Eina_Bool cacheable = EINA_FALSE; - /* Try caching buffer only for static images. */ - if (evas_cache_vg_anim_frame_count_get(pd->vg_entry) == 0) + /* Try caching buffer only for first and last frames + because it's an overhead task if it caches all frame images. + 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; if (pd->vg_entry) @@ -745,7 +757,7 @@ _efl_canvas_vg_object_render(Evas_Object *eo_obj EINA_UNUSED, _user_vg_entry_render(obj, pd, engine, output, context, surface, obj->cur->geometry.x + x, obj->cur->geometry.y + y, - obj->cur->geometry.w, obj->cur->geometry.h, do_async, cacheable); + obj->cur->geometry.w, obj->cur->geometry.h, do_async); } pd->changed = EINA_FALSE; } diff --git a/src/lib/evas/canvas/evas_vg_private.h b/src/lib/evas/canvas/evas_vg_private.h index 2a1dbfa..a6a2714 100644 --- a/src/lib/evas/canvas/evas_vg_private.h +++ b/src/lib/evas/canvas/evas_vg_private.h @@ -15,6 +15,7 @@ typedef struct _Vg_Cache { Eina_Hash *vfd_hash; Eina_Hash *vg_entry_hash; + Eina_List *vg_surface_keys; int ref; } Vg_Cache; @@ -154,6 +155,7 @@ Eina_Bool evas_cache_vg_anim_sector_set(const Vg_Cache_Entry* Eina_Bool evas_cache_vg_anim_sector_get(const Vg_Cache_Entry* vg_entry, const char *name, int* startframe, int* endframe); unsigned int evas_cache_vg_anim_frame_count_get(const Vg_Cache_Entry *vg_entry); Eina_Size2D evas_cache_vg_entry_default_size_get(const Vg_Cache_Entry *vg_entry); +void * evas_cache_vg_surface_key_get(Efl_Canvas_Vg_Node *root, int w, int h, int frame_idx); void efl_canvas_vg_node_vg_obj_set(Efl_VG *node, Efl_VG *vg_obj, Efl_Canvas_Vg_Object_Data *vd); void efl_canvas_vg_node_change(Efl_VG *node); void efl_canvas_vg_container_vg_obj_update(Efl_VG *obj, Efl_Canvas_Vg_Node_Data *nd); diff --git a/src/lib/evas/vg/evas_vg_cache.c b/src/lib/evas/vg/evas_vg_cache.c index 5c0242d..2ef31bd 100644 --- a/src/lib/evas/vg/evas_vg_cache.c +++ b/src/lib/evas/vg/evas_vg_cache.c @@ -269,12 +269,45 @@ evas_cache_vg_init(void) vg_cache->ref++; } +void * +evas_cache_vg_surface_key_get(Efl_Canvas_Vg_Node *root, int w, int h, int frame_idx) +{ + //This make a unique key pointer by arguments. + Eina_Strbuf *hash_key = eina_strbuf_new(); + eina_strbuf_append_printf(hash_key, "%p/%d/%d/%d", root, w, h, frame_idx); + const char *new_key = eina_strbuf_string_get(hash_key); + if (!new_key) return NULL; + + Eina_List *l; + char *key; + EINA_LIST_FOREACH(vg_cache->vg_surface_keys, l, key) + { + //Exisiting key! + if (!strcmp(key, new_key)) + { + eina_strbuf_free(hash_key); + return key; + } + } + + //New key comes. + key = eina_strbuf_string_steal(hash_key); + vg_cache->vg_surface_keys = eina_list_append(vg_cache->vg_surface_keys, key); + return (void *) key; +} + void evas_cache_vg_shutdown(void) { if (!vg_cache) return; vg_cache->ref--; if (vg_cache->ref > 0) return; + + char *key; + EINA_LIST_FREE(vg_cache->vg_surface_keys, key) + free(key); + eina_list_free(vg_cache->vg_surface_keys); + eina_hash_free(vg_cache->vfd_hash); eina_hash_free(vg_cache->vg_entry_hash); free(vg_cache);