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:22:54 +0900
commita05cfedaa9e42518b56edffcc9b51687d39439c9 (patch)
tree66ad73fcd117b4f453c8a47b1158020b173a4e10
parent025dca5c77fcb55b45c9709758312883cf1fe9bb (diff)
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 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
144 // detach/free the old root_node 144 // detach/free the old root_node
145 if (pd->user_entry && pd->user_entry->root) 145 if (pd->user_entry && pd->user_entry->root)
146 { 146 {
147 // drop any surface cache attached to it.
148 ENFN->ector_surface_cache_drop(_evas_engine_context(obj->layer->evas), pd->user_entry->root);
147 efl_canvas_vg_node_vg_obj_set(pd->user_entry->root, NULL, NULL); 149 efl_canvas_vg_node_vg_obj_set(pd->user_entry->root, NULL, NULL);
148 efl_replace(&pd->user_entry->root, NULL); 150 efl_replace(&pd->user_entry->root, NULL);
149 } 151 }
@@ -166,8 +168,6 @@ _efl_canvas_vg_object_root_node_set(Eo *eo_obj, Efl_Canvas_Vg_Object_Data *pd, E
166 } 168 }
167 else if (pd->user_entry) 169 else if (pd->user_entry)
168 { 170 {
169 // drop any surface cache attached to it.
170 ENFN->ector_surface_cache_drop(_evas_engine_context(obj->layer->evas), pd->user_entry->root);
171 free(pd->user_entry); 171 free(pd->user_entry);
172 pd->user_entry = NULL; 172 pd->user_entry = NULL;
173 } 173 }
@@ -345,7 +345,6 @@ _efl_canvas_vg_object_efl_object_invalidate(Eo *eo_obj, Efl_Canvas_Vg_Object_Dat
345 if (pd->user_entry) 345 if (pd->user_entry)
346 { 346 {
347 Vg_User_Entry *user_entry = pd->user_entry; 347 Vg_User_Entry *user_entry = pd->user_entry;
348
349 ENFN->ector_surface_cache_drop(ENC, user_entry->root); 348 ENFN->ector_surface_cache_drop(ENC, user_entry->root);
350 free(pd->user_entry); 349 free(pd->user_entry);
351 } 350 }
@@ -492,8 +491,8 @@ _evas_vg_render(Evas_Object_Protected_Data *obj, Efl_Canvas_Vg_Object_Data *pd,
492//renders a vg_tree to an offscreen buffer and push it to the cache. 491//renders a vg_tree to an offscreen buffer and push it to the cache.
493static void * 492static void *
494_render_to_buffer(Evas_Object_Protected_Data *obj, Efl_Canvas_Vg_Object_Data *pd, 493_render_to_buffer(Evas_Object_Protected_Data *obj, Efl_Canvas_Vg_Object_Data *pd,
495 void *engine, Efl_VG *root, int w, int h, void *buffer, 494 void *engine, Efl_VG *root, int w, int h, void *buffer, void *ckey,
496 Eina_Bool do_async, Eina_Bool cacheable) 495 Eina_Bool do_async)
497{ 496{
498 Ector_Surface *ector; 497 Ector_Surface *ector;
499 RGBA_Draw_Context *context; 498 RGBA_Draw_Context *context;
@@ -534,11 +533,8 @@ _render_to_buffer(Evas_Object_Protected_Data *obj, Efl_Canvas_Vg_Object_Data *pd
534 ENFN->ector_end(engine, buffer, context, ector, do_async); 533 ENFN->ector_end(engine, buffer, context, ector, do_async);
535 evas_common_draw_context_free(context); 534 evas_common_draw_context_free(context);
536 535
537 if (buffer_created && cacheable) 536 if (buffer_created && ckey)
538 { 537 ENFN->ector_surface_cache_set(engine, ckey, buffer);
539 //Use root as a cache key.
540 ENFN->ector_surface_cache_set(engine, root, buffer);
541 }
542 538
543 return buffer; 539 return buffer;
544} 540}
@@ -579,8 +575,8 @@ _cache_vg_entry_render(Evas_Object_Protected_Data *obj,
579 Vg_Cache_Entry *vg_entry = pd->vg_entry; 575 Vg_Cache_Entry *vg_entry = pd->vg_entry;
580 Efl_VG *root; 576 Efl_VG *root;
581 Eina_Position2D offset = {0, 0}; //Offset after keeping aspect ratio. 577 Eina_Position2D offset = {0, 0}; //Offset after keeping aspect ratio.
582 Eina_Bool drop_cache = EINA_FALSE;
583 void *buffer = NULL; 578 void *buffer = NULL;
579 void *key = NULL;
584 580
585 evas_cache_vg_entry_value_provider_update(pd->vg_entry, efl_key_data_get(obj->object, "_vg_value_providers")); 581 evas_cache_vg_entry_value_provider_update(pd->vg_entry, efl_key_data_get(obj->object, "_vg_value_providers"));
586 582
@@ -616,7 +612,23 @@ _cache_vg_entry_render(Evas_Object_Protected_Data *obj,
616 //Size is changed, cached data is invalid. 612 //Size is changed, cached data is invalid.
617 if ((size.w != vg_entry->w) || (size.h != vg_entry->h)) 613 if ((size.w != vg_entry->w) || (size.h != vg_entry->h))
618 { 614 {
619 drop_cache = EINA_TRUE; 615//Not necessary, but this might be helpful for precise caching.
616#if 0
617 if (cacheable)
618 {
619 //if the size doesn't match, drop previous cache surface.
620 key = evas_cache_vg_surface_key_get(pd->vg_entry->root, vg_entry->w, vg_entry->h, 0);
621 if (key) ENFN->ector_surface_cache_drop(engine, key);
622
623 //Animatable... Try to drop the last frame image.
624 int last_frame = (int) (evas_cache_vg_anim_frame_count_get(pd->vg_entry) - 1);
625 if (last_frame > 0)
626 {
627 key = evas_cache_vg_surface_key_get(pd->vg_entry->root, vg_entry->w, vg_entry->h, last_frame);
628 if (key) ENFN->ector_surface_cache_drop(engine, key);
629 }
630 }
631#endif
620 vg_entry = evas_cache_vg_entry_resize(vg_entry, size.w, size.h); 632 vg_entry = evas_cache_vg_entry_resize(vg_entry, size.w, size.h);
621 evas_cache_vg_entry_del(pd->vg_entry); 633 evas_cache_vg_entry_del(pd->vg_entry);
622 pd->vg_entry = vg_entry; 634 pd->vg_entry = vg_entry;
@@ -629,27 +641,25 @@ _cache_vg_entry_render(Evas_Object_Protected_Data *obj,
629 if (offset.y > 0) offset.y /= 2; 641 if (offset.y > 0) offset.y /= 2;
630 w = size.w; 642 w = size.w;
631 h = size.h; 643 h = size.h;
632
633 } 644 }
634 root = evas_cache_vg_tree_get(vg_entry, pd->frame_idx); 645 root = evas_cache_vg_tree_get(vg_entry, pd->frame_idx);
635 if (!root) return; 646 if (!root) return;
636 647
637 if (cacheable) 648 if (cacheable)
638 { 649 {
639 //if the size doesn't match, drop previous cache surface. 650 key = evas_cache_vg_surface_key_get(root, w, h, pd->frame_idx);
640 if (drop_cache) 651 if (key) buffer = ENFN->ector_surface_cache_get(engine, key);
641 ENFN->ector_surface_cache_drop(engine, (void *) root);
642 //Cache Hit!
643 else
644 buffer = ENFN->ector_surface_cache_get(engine, (void *) root);
645 } 652 }
646 653
647 if (!buffer) 654 if (!buffer)
648 buffer = _render_to_buffer(obj, pd, engine, root, w, h, NULL, 655 {
649 do_async, cacheable); 656 buffer = _render_to_buffer(obj, pd, engine, root, w, h, NULL, key, do_async);
657 }
650 else 658 else
651 //cache reference was increased when we get the cache. 659 {
652 ENFN->ector_surface_cache_drop(engine, (void *) root); 660 //cache reference was increased when we get the cache.
661 if (key) ENFN->ector_surface_cache_drop(engine, key);
662 }
653 663
654 _render_buffer_to_screen(obj, 664 _render_buffer_to_screen(obj,
655 engine, output, context, surface, 665 engine, output, context, surface,
@@ -662,8 +672,7 @@ static void
662_user_vg_entry_render(Evas_Object_Protected_Data *obj, 672_user_vg_entry_render(Evas_Object_Protected_Data *obj,
663 Efl_Canvas_Vg_Object_Data *pd, 673 Efl_Canvas_Vg_Object_Data *pd,
664 void *engine, void *output, void *context, void *surface, 674 void *engine, void *output, void *context, void *surface,
665 int x, int y, int w, int h, Eina_Bool do_async, 675 int x, int y, int w, int h, Eina_Bool do_async)
666 Eina_Bool cacheable)
667{ 676{
668 Vg_User_Entry *user_entry = pd->user_entry; 677 Vg_User_Entry *user_entry = pd->user_entry;
669 678
@@ -679,14 +688,13 @@ _user_vg_entry_render(Evas_Object_Protected_Data *obj,
679 //if the buffer is not created yet 688 //if the buffer is not created yet
680 void *buffer = NULL; 689 void *buffer = NULL;
681 690
682 if (cacheable)
683 buffer = ENFN->ector_surface_cache_get(engine, user_entry->root); 691 buffer = ENFN->ector_surface_cache_get(engine, user_entry->root);
684 692
685 if (!buffer) 693 if (!buffer)
686 { 694 {
687 // render to the buffer 695 // render to the buffer
688 buffer = _render_to_buffer(obj, pd, engine, user_entry->root, 696 buffer = _render_to_buffer(obj, pd, engine, user_entry->root,
689 w, h, buffer, do_async, cacheable); 697 w, h, buffer, user_entry->root, do_async);
690 } 698 }
691 else 699 else
692 { 700 {
@@ -694,8 +702,8 @@ _user_vg_entry_render(Evas_Object_Protected_Data *obj,
694 if (pd->changed) 702 if (pd->changed)
695 buffer = _render_to_buffer(obj, pd, engine, 703 buffer = _render_to_buffer(obj, pd, engine,
696 user_entry->root, 704 user_entry->root,
697 w, h, buffer, 705 w, h, buffer, NULL,
698 do_async, EINA_FALSE); 706 do_async);
699 //cache reference was increased when we get the cache. 707 //cache reference was increased when we get the cache.
700 ENFN->ector_surface_cache_drop(engine, user_entry->root); 708 ENFN->ector_surface_cache_drop(engine, user_entry->root);
701 } 709 }
@@ -704,7 +712,7 @@ _user_vg_entry_render(Evas_Object_Protected_Data *obj,
704 engine, output, context, surface, 712 engine, output, context, surface,
705 buffer, 713 buffer,
706 x, y, w, h, 714 x, y, w, h,
707 do_async, cacheable); 715 do_async, EINA_TRUE);
708} 716}
709 717
710static void 718static void
@@ -729,8 +737,12 @@ _efl_canvas_vg_object_render(Evas_Object *eo_obj EINA_UNUSED,
729 //Cache surface? 737 //Cache surface?
730 Eina_Bool cacheable = EINA_FALSE; 738 Eina_Bool cacheable = EINA_FALSE;
731 739
732 /* Try caching buffer only for static images. */ 740 /* Try caching buffer only for first and last frames
733 if (evas_cache_vg_anim_frame_count_get(pd->vg_entry) == 0) 741 because it's an overhead task if it caches all frame images.
742 We assume the first and last frame images are the most resusable
743 in generic scenarios. */
744 if (pd->frame_idx == 0 ||
745 (pd->frame_idx == (int) (evas_cache_vg_anim_frame_count_get(pd->vg_entry) - 1)))
734 cacheable = EINA_TRUE; 746 cacheable = EINA_TRUE;
735 747
736 if (pd->vg_entry) 748 if (pd->vg_entry)
@@ -745,7 +757,7 @@ _efl_canvas_vg_object_render(Evas_Object *eo_obj EINA_UNUSED,
745 _user_vg_entry_render(obj, pd, 757 _user_vg_entry_render(obj, pd,
746 engine, output, context, surface, 758 engine, output, context, surface,
747 obj->cur->geometry.x + x, obj->cur->geometry.y + y, 759 obj->cur->geometry.x + x, obj->cur->geometry.y + y,
748 obj->cur->geometry.w, obj->cur->geometry.h, do_async, cacheable); 760 obj->cur->geometry.w, obj->cur->geometry.h, do_async);
749 } 761 }
750 pd->changed = EINA_FALSE; 762 pd->changed = EINA_FALSE;
751} 763}
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
15{ 15{
16 Eina_Hash *vfd_hash; 16 Eina_Hash *vfd_hash;
17 Eina_Hash *vg_entry_hash; 17 Eina_Hash *vg_entry_hash;
18 Eina_List *vg_surface_keys;
18 int ref; 19 int ref;
19} Vg_Cache; 20} Vg_Cache;
20 21
@@ -154,6 +155,7 @@ Eina_Bool evas_cache_vg_anim_sector_set(const Vg_Cache_Entry*
154Eina_Bool evas_cache_vg_anim_sector_get(const Vg_Cache_Entry* vg_entry, const char *name, int* startframe, int* endframe); 155Eina_Bool evas_cache_vg_anim_sector_get(const Vg_Cache_Entry* vg_entry, const char *name, int* startframe, int* endframe);
155unsigned int evas_cache_vg_anim_frame_count_get(const Vg_Cache_Entry *vg_entry); 156unsigned int evas_cache_vg_anim_frame_count_get(const Vg_Cache_Entry *vg_entry);
156Eina_Size2D evas_cache_vg_entry_default_size_get(const Vg_Cache_Entry *vg_entry); 157Eina_Size2D evas_cache_vg_entry_default_size_get(const Vg_Cache_Entry *vg_entry);
158void * evas_cache_vg_surface_key_get(Efl_Canvas_Vg_Node *root, int w, int h, int frame_idx);
157void efl_canvas_vg_node_vg_obj_set(Efl_VG *node, Efl_VG *vg_obj, Efl_Canvas_Vg_Object_Data *vd); 159void efl_canvas_vg_node_vg_obj_set(Efl_VG *node, Efl_VG *vg_obj, Efl_Canvas_Vg_Object_Data *vd);
158void efl_canvas_vg_node_change(Efl_VG *node); 160void efl_canvas_vg_node_change(Efl_VG *node);
159void efl_canvas_vg_container_vg_obj_update(Efl_VG *obj, Efl_Canvas_Vg_Node_Data *nd); 161void 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)
269 vg_cache->ref++; 269 vg_cache->ref++;
270} 270}
271 271
272void *
273evas_cache_vg_surface_key_get(Efl_Canvas_Vg_Node *root, int w, int h, int frame_idx)
274{
275 //This make a unique key pointer by arguments.
276 Eina_Strbuf *hash_key = eina_strbuf_new();
277 eina_strbuf_append_printf(hash_key, "%p/%d/%d/%d", root, w, h, frame_idx);
278 const char *new_key = eina_strbuf_string_get(hash_key);
279 if (!new_key) return NULL;
280
281 Eina_List *l;
282 char *key;
283 EINA_LIST_FOREACH(vg_cache->vg_surface_keys, l, key)
284 {
285 //Exisiting key!
286 if (!strcmp(key, new_key))
287 {
288 eina_strbuf_free(hash_key);
289 return key;
290 }
291 }
292
293 //New key comes.
294 key = eina_strbuf_string_steal(hash_key);
295 vg_cache->vg_surface_keys = eina_list_append(vg_cache->vg_surface_keys, key);
296 return (void *) key;
297}
298
272void 299void
273evas_cache_vg_shutdown(void) 300evas_cache_vg_shutdown(void)
274{ 301{
275 if (!vg_cache) return; 302 if (!vg_cache) return;
276 vg_cache->ref--; 303 vg_cache->ref--;
277 if (vg_cache->ref > 0) return; 304 if (vg_cache->ref > 0) return;
305
306 char *key;
307 EINA_LIST_FREE(vg_cache->vg_surface_keys, key)
308 free(key);
309 eina_list_free(vg_cache->vg_surface_keys);
310
278 eina_hash_free(vg_cache->vfd_hash); 311 eina_hash_free(vg_cache->vfd_hash);
279 eina_hash_free(vg_cache->vg_entry_hash); 312 eina_hash_free(vg_cache->vg_entry_hash);
280 free(vg_cache); 313 free(vg_cache);