summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHermet Park <hermetpark@gmail.com>2019-12-13 17:22:54 +0900
committerHermet Park <hermetpark@gmail.com>2019-12-13 17:25:26 +0900
commit4f99f9f2bf17b437aa975c3875812529c2759707 (patch)
tree755ec556d70a8babf43433fb1786473f23d6bdd2
parent3372a701d301fef9b1d033b97df0f38de130456f (diff)
downloadefl-4f99f9f2bf17b437aa975c3875812529c2759707.tar.gz
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.
-rw-r--r--src/lib/evas/canvas/efl_canvas_vg_object.c78
-rw-r--r--src/lib/evas/canvas/evas_vg_private.h2
-rw-r--r--src/lib/evas/vg/evas_vg_cache.c33
3 files changed, 80 insertions, 33 deletions
diff --git a/src/lib/evas/canvas/efl_canvas_vg_object.c b/src/lib/evas/canvas/efl_canvas_vg_object.c
index 740cfacc6c..83a59bd6fe 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 2a1dbfa0d5..a6a27142ed 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 5c0242db23..2ef31bded2 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);