raster pushed a commit to branch master. http://git.enlightenment.org/core/efl.git/commit/?id=54850ccd2f630b1397a4268088ba53b3305ffcb7
commit 54850ccd2f630b1397a4268088ba53b3305ffcb7 Author: Ali Alzyod <ali198...@gmail.com> Date: Fri Jul 24 10:36:27 2020 +0100 evas: font glyphs texture garbage collector Summary: Introduce two public APIS ``` #define EVAS_FONT_DATA_CACHE_TEXTURE 0x01 /** * Set the limit in bytes for memory allocated by font glyphs in evas. * @param[in] bytes cache size in bytes, pass negative value to ignore the limit. * @param[in] options for caching, pass 0x1 to set the texture cache (in case of accelerated rendering). * * @since 1.24 */ EAPI void evas_font_data_cache_set(signed long long int byte, int options); /** * @} */ /** * Get the limit in bytes for memory allocated by font glyphs in evas. * @param[in] options for caching, pass 0x1 to get the texture cache (in case of accelerated rendering). * @return Returns font allocated memory cache limit, if value is negative this means no limit. * @since 1.24 */ EAPI signed long long int evas_font_data_cache_get(int options); ``` Test Plan: elementary_test => Text Memory You need a tool to observe Video memory allocation. 1- If you have detected Graphics card then use **radiontop** or **nvidia-smi** ). 2- If you have Integrated Graphics card, then you can detect memory allocation on RAM use. ---------------------------------------------- this example allows only 50 MByte Video memory texture allocated by font glyphs ``` #include <Elementary.h> typedef struct _APP { Evas_Object *tb1; Evas_Object *btnLoad; } APP; char *text = "<align=center><color=#4DE0FFFF underline=on underline_color=#4DE0FFFF><a href='tel:1234567890'>1234567890</a></color>๐๐๐๐คฃ๐๐๐ ๐๐๐๐๐๐๐๐๐๐โบ๐๐ค๐ค๐๐๐ถ๐๐๐ฃ๐ฅ๐ฎ๐ค๐ฏ๐ช๐ซ๐ด๐๐ค๐๐๐๐คค๐๐๐๐๐๐ค๐ฒโน๐๐๐๐๐ค๐ข๐ญ๐ฆ๐ง๐จ๐ฉ๐ฌ๐ฐ๐ฑ๐ณ๐ต๐ก๐ ๐๐ค ๐คก๐คฅ๐ท๐ค๐ค๐คข๐คงโป๐๐ฟ๐น๐บ๐โ ๐ป๐ฝ๐พ๐ค๐ฉ๐บ๐ธ๐น๐ป๐ผ๐ฝ๐๐ฟ๐พ๐๐๐๐ฆ๐ง๐จ๐ฉ๐ต๐ถ๐ผ๐จโโ๏ธ๐ฉโโ๏ธ๐จโ๐๐ฉโ๐๐จโ๐ซ๐ฉโ๐ซ๐จโโ๐ฉโโ๐จโ๐พ๐ฉโ๐พ๐จโ๐ณ๐ฉโ๐ณ๐จโ๐ง๐ฉโ๐ง๐จโ๐ญ๐ฉโ๐ญ๐จโ๐ผ๐ฉโ๐ผ๐จโ๐ฌ๐ฉโ๐ฌ๐จโ๐ป๐ฉโ๐ป๐จโ๐ค๐ฉโ๐ค๐จโ๐จ๐ฉโ๐จ๐จโโ๏ธ๐ฉโโ๏ธ๐จโ๐๐ฉโ๐๐จโ๐๐ฉโ๐๐ฎโโ๏ธ๐ฎโโ๏ธ๐ต๏ธโโ๏ธ๐ต๏ธโโ๏ธ๐โโ๏ธ๐โโ๏ธ๐ทโโ๏ธ๐ทโโ๏ธ๐ณโโ๏ธ๐ณโโ๏ธ๐ฑโโ๏ธ๐ฑโโ๏ธ๐ ๐คถ๐ธ๐คด๐ฐ๐คต๐คฐ๐ฒ๐โโ๏ธ๐โโ๏ธ๐โโ๏ธ๐โโ๏ธ๐ โโ๏ธ๐ โโ๏ธ๐โโ๏ธ๐โโ๏ธ๐โโ๏ธ๐โโ๏ธ๐โโ๏ธ๐โโ๏ธ๐โโ๏ธ๐โโ๏ธ๐คฆโโ๏ธ๐คฆโโ๏ธ๐คทโโ๏ธ๐คทโโ๏ธ๐โโ๏ธ๐โโ๏ธ๐โโ๏ธ๐โโ๏ธ๐ถโโ๏ธ๐ถโ [...] int font_size = 200; int counter = 0; void _button_clicked(void *data, Evas_Object *obj, void *event_info) { APP *app = data; font_size -= 5; Evas_Textblock_Style *style = evas_textblock_style_new(); char buffer[100] = {0}; sprintf(buffer, "DEFAULT='font=NotoColorEmoji font_size=%i color=red ellipsis=-1.0 wrap=mixed'", font_size); evas_textblock_style_set(style, buffer); evas_object_textblock_style_set(app->tb1, style); evas_textblock_style_free(style); style = NULL; } EAPI_MAIN int elm_main(int argc EINA_UNUSED, char **argv EINA_UNUSED) { APP *app = calloc(1, sizeof(APP)); Evas_Object *win, *scroller1, *scroller2, *box; elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED); win = elm_win_util_standard_add("", ""); elm_win_autodel_set(win, EINA_TRUE); box = elm_box_add(win); evas_object_size_hint_weight_set(box, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); evas_object_size_hint_align_set(box, EVAS_HINT_FILL, EVAS_HINT_FILL); scroller1 = elm_scroller_add(win); evas_object_size_hint_weight_set(scroller1, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); evas_object_size_hint_align_set(scroller1, EVAS_HINT_FILL, EVAS_HINT_FILL); evas_font_data_cache_set(50 * 1024* 1024, EVAS_FONT_DATA_CACHE_TEXTURE ); app->tb1 = evas_object_textblock_add(win); Evas_Textblock_Style *style = evas_textblock_style_new(); char buffer[100] = {0}; sprintf(buffer, "DEFAULT='font=NotoColorEmoji font_size=%i color=red ellipsis=-1.0 wrap=mixed'", font_size); evas_textblock_style_set(style, buffer); evas_object_textblock_style_set(app->tb1, style); evas_textblock_style_free(style); style = NULL; evas_font_cache_set(evas_object_evas_get(app->tb1), 0); int w,h; evas_object_textblock_text_markup_set(app->tb1, ""); evas_object_size_hint_min_set(app->tb1, 400, 400); elm_object_content_set(scroller1, app->tb1); elm_box_pack_end(box, scroller1); elm_object_content_set(win, box); app->btnLoad = elm_button_add(win); elm_object_text_set(app->btnLoad, "Scale Font"); evas_object_smart_callback_add(app->btnLoad, "clicked", _button_clicked, app); evas_object_show(app->btnLoad); evas_object_move(app->btnLoad, 0, 20); evas_object_resize(app->btnLoad, 150, 20); evas_object_textblock_text_markup_set(app->tb1, text); evas_object_textblock_size_formatted_get(app->tb1, &w, &h); evas_object_size_hint_min_set(app->tb1, 400, w/400 + h + 150); evas_object_resize(win, 400, 400); evas_object_show(box); evas_object_show(scroller1); evas_object_show(scroller2); evas_object_show(win); elm_run(); return 0; } ELM_MAIN() ``` Reviewers: raster, woohyun, zmike, cedric, bu5hm4n, Hermet Subscribers: cedric, #reviewers, #committers Tags: #efl Maniphest Tasks: T8737 Differential Revision: https://phab.enlightenment.org/D11943 --- src/bin/elementary/test.c | 2 + src/bin/elementary/test_label.c | 118 +++++++++++++++++++++ src/lib/evas/Evas_Common.h | 33 ++++++ src/lib/evas/canvas/evas_render.c | 5 + src/lib/evas/common/evas_font_main.c | 22 +++- src/lib/evas/include/evas_common_private.h | 1 + src/lib/evas/include/evas_private.h | 2 + .../evas/engines/gl_common/evas_gl_common.h | 3 + src/modules/evas/engines/gl_common/evas_gl_font.c | 26 ++++- .../evas/engines/gl_common/evas_gl_texture.c | 5 + src/modules/evas/engines/gl_generic/evas_engine.c | 37 +++++++ .../evas/engines/software_generic/evas_engine.c | 7 ++ 12 files changed, 259 insertions(+), 2 deletions(-) diff --git a/src/bin/elementary/test.c b/src/bin/elementary/test.c index 1acf333dcf..d0d374ece4 100644 --- a/src/bin/elementary/test.c +++ b/src/bin/elementary/test.c @@ -241,6 +241,7 @@ void test_label(void *data, Evas_Object *obj, void *event_info); void test_label_slide(void *data, Evas_Object *obj, void *event_info); void test_label_wrap(void *data, Evas_Object *obj, void *event_info); void test_textblock_fit(void *data, Evas_Object *obj, void *event_info); +void test_text_memory(void *data, Evas_Object *obj, void *event_info); void test_label_ellipsis(void *data, Evas_Object *obj, void *event_info); void test_label_colors(void *data, Evas_Object *obj, void *event_info); void test_label_emoji(void *data, Evas_Object *obj, void *event_info); @@ -1220,6 +1221,7 @@ add_tests: ADD_TEST(NULL, "Text", "Label Slide", test_label_slide); ADD_TEST(NULL, "Text", "Label Wrap", test_label_wrap); ADD_TEST(NULL, "Text", "Textblock Fit", test_textblock_fit); + ADD_TEST(NULL, "Text", "Text Memory", test_text_memory); ADD_TEST(NULL, "Text", "Label Ellipsis", test_label_ellipsis); ADD_TEST(NULL, "Text", "Label Colors", test_label_colors); ADD_TEST(NULL, "Text", "Label Emoji", test_label_emoji); diff --git a/src/bin/elementary/test_label.c b/src/bin/elementary/test_label.c index 414058d9ad..d8d1a80698 100644 --- a/src/bin/elementary/test_label.c +++ b/src/bin/elementary/test_label.c @@ -543,6 +543,124 @@ test_textblock_fit(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *e evas_object_show(app->win); } +/*** Text Memory Configuration **************************************************************/ +enum BUTTON_MEM{ + BUTTON_MEM_SET_TEXT = 0, + BUTTON_MEM_APPLY_MEM = 1, + BUTTON_MEM_APPLY_FONT_SIZE = 2, + BUTTON_MEM_ALL = BUTTON_MEM_APPLY_FONT_SIZE+1, +}; + +char* BUTTON_MEM_STR[BUTTON_MEM_ALL] ={ + "Load Emojis Text", + "Memory Limit(MB)", + "Font Size" +}; + +char *content = "<align=center>๐๐๐๐คฃ๐๐๐ ๐๐๐๐๐๐๐๐๐๐โบ๐๐ค๐ค๐๐๐ถ๐๐๐ฃ๐ฅ๐ฎ๐ค๐ฏ๐ช๐ซ๐ด๐๐ค๐๐๐๐คค๐๐๐๐๐๐ค๐ฒโน๐๐๐๐๐ค๐ข๐ญ๐ฆ๐ง๐จ๐ฉ๐ฌ๐ฐ๐ฑ๐ณ๐ต๐ก๐ ๐๐ค ๐คก๐คฅ๐ท๐ค๐ค๐คข๐คงโป๐๐ฟ๐น๐บ๐โ ๐ป๐ฝ๐พ๐ค๐ฉ๐บ๐ธ๐น๐ป๐ผ๐ฝ๐๐ฟ๐พ๐๐๐๐ฆ๐ง๐จ๐ฉ๐ต๐ถ๐ผ๐จโโ๏ธ๐ฉโโ๏ธ๐จโ๐๐ฉโ๐๐จโ๐ซ๐ฉโ๐ซ๐จโโ๐ฉโโ๐จโ๐พ๐ฉโ๐พ๐จโ๐ณ๐ฉโ๐ณ๐จโ๐ง๐ฉโ๐ง๐จโ๐ญ๐ฉโ๐ญ๐จโ๐ผ๐ฉโ๐ผ๐จโ๐ฌ๐ฉโ๐ฌ๐จโ๐ป๐ฉโ๐ป๐จโ๐ค๐ฉโ๐ค๐จโ๐จ๐ฉโ๐จ๐จโโ๏ธ๐ฉโโ๏ธ๐จโ๐๐ฉโ๐๐จโ๐๐ฉโ๐๐ฎโโ๏ธ๐ฎโโ๏ธ๐ต๏ธโโ๏ธ๐ต๏ธโโ๏ธ๐โโ๏ธ๐โโ๏ธ๐ทโโ๏ธ๐ทโโ๏ธ๐ณโโ๏ธ๐ณโโ๏ธ๐ฑโโ๏ธ๐ฑโโ๏ธ๐ ๐คถ๐ธ๐คด๐ฐ๐คต๐คฐ๐ฒ๐โโ๏ธ๐โโ๏ธ๐โโ๏ธ๐โโ๏ธ๐ โโ๏ธ๐ โโ๏ธ๐โโ๏ธ๐โโ๏ธ๐โโ๏ธ๐โโ๏ธ๐โโ๏ธ๐โโ๏ธ๐โโ๏ธ๐โโ๏ธ๐คฆโโ๏ธ๐คฆโโ๏ธ๐คทโโ๏ธ๐คทโโ๏ธ๐โโ๏ธ๐โโ๏ธ๐โโ๏ธ๐โโ๏ธ๐ถโโ๏ธ๐ถโโ๏ธ๐โโ๏ธ๐โโ๏ธ๐๐บ๐ฏโโ๏ธ๐ฏโโ๏ธ๐ด๐ฃ๐ค๐ฅ๐ซ๐ฌ๐ญ๐๐๐ช๐จโ๐ฉโ๐ง๐จโ๐ฉโ๐งโ๐ฆ๐จโ๐ฉโ๐ฆโ๐ฆ๐จโ๐ฉโ๐งโ๐ง๐จโ๐ฆ๐จโ๐ฆโ๐ฆ๐จโ๐ง๐จโ๐งโ๐ฆ๐จโ๐งโ๐ง๐ฉโ๐ฆ๐ฉโ๐ฆโ๐ฆ๐ฉโ๐ง๐ฉโ๐งโ๐ฆ๐ฉโ๐งโ๐ง๐ช๐คณ๐๐โ [...] + +typedef struct _APP_MEM +{ + Evas_Object *win, *box, *main_entry; + Eo *btn[BUTTON_MEM_ALL]; + Eo *entry[BUTTON_MEM_ALL]; +} APP_MEM; +APP_MEM *app_mem; + +static void _btn_clicked_mem(void *data EINA_UNUSED, Eo *obj, void *eventInfo EINA_UNUSED){ + if (obj == app_mem->btn[BUTTON_MEM_SET_TEXT]) + { + elm_object_text_set(app_mem->main_entry, content); + } + else if (obj == app_mem->btn[BUTTON_MEM_APPLY_MEM]) + { + int size = atoi(elm_object_text_get(app_mem->entry[BUTTON_MEM_APPLY_MEM])); + if (size > 0 && size < 4000) + { + evas_font_data_cache_set(EVAS_FONT_DATA_CACHE_TEXTURE, size * 1024 * 1024); + } + else + { + elm_object_text_set(app_mem->entry[BUTTON_MEM_APPLY_MEM], "NAN"); + } + } + else if (obj == app_mem->btn[BUTTON_MEM_APPLY_FONT_SIZE]) + { + int font_size = atoi(elm_object_text_get(app_mem->entry[BUTTON_MEM_APPLY_FONT_SIZE])); + if (font_size > 0 && font_size < 1000) + { + char sfont_size[256] = {0}; + sprintf(sfont_size,"DEFAULT='font_size=%i'", font_size); + elm_entry_text_style_user_push(app_mem->main_entry, sfont_size); + } + else + { + elm_object_text_set(app_mem->entry[BUTTON_MEM_APPLY_FONT_SIZE], "NAN"); + } + } +} + +void +test_text_memory(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) +{ + app_mem = calloc(sizeof(APP), 1); + + elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED); + + app_mem->win = elm_win_util_standard_add("Main", "App"); + elm_win_autodel_set(app_mem->win, EINA_TRUE); + + app_mem->box = elm_box_add(app_mem->win); + app_mem->main_entry = elm_entry_add(app_mem->box); + + evas_object_size_hint_weight_set(app_mem->box, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(app_mem->box, EVAS_HINT_FILL, EVAS_HINT_FILL); + + app_mem->btn[BUTTON_MEM_SET_TEXT] = elm_button_add(app_mem->box); + evas_object_smart_callback_add(app_mem->btn[BUTTON_MEM_SET_TEXT], "clicked", _btn_clicked_mem, NULL); + elm_object_text_set(app_mem->btn[BUTTON_MEM_SET_TEXT], BUTTON_MEM_STR[BUTTON_MEM_SET_TEXT]); + evas_object_size_hint_align_set(app_mem->btn[BUTTON_MEM_SET_TEXT], EVAS_HINT_FILL, EVAS_HINT_FILL); + elm_box_pack_end(app_mem->box, app_mem->btn[BUTTON_MEM_SET_TEXT]); + evas_object_show(app_mem->btn[BUTTON_MEM_SET_TEXT]); + + elm_entry_scrollable_set(app_mem->main_entry, EINA_TRUE); + evas_object_show(app_mem->main_entry); + evas_object_show(app_mem->box); + + elm_box_pack_end(app_mem->box, app_mem->main_entry); + evas_object_smart_callback_add(app_mem->btn[BUTTON_MEM_SET_TEXT], "clicked", _btn_clicked_mem, NULL); + evas_object_show(app_mem->btn[BUTTON_MEM_SET_TEXT]); + + elm_win_resize_object_add(app_mem->win, app_mem->box); + evas_object_resize(app_mem->win, 320, 320); + + elm_entry_text_style_user_push(app_mem->main_entry, "DEFAULT='font_size=20'"); + + for(int i = BUTTON_MEM_APPLY_MEM ; i < BUTTON_MEM_ALL ; i++) + { + app_mem->btn[i] = elm_button_add(app_mem->box); + app_mem->entry[i] = elm_entry_add(app_mem->box); + evas_object_smart_callback_add(app_mem->btn[i], "clicked", _btn_clicked_mem, NULL); + elm_object_text_set(app_mem->btn[i], BUTTON_MEM_STR[i]); + elm_box_pack_end(app_mem->box, app_mem->btn[i]); + elm_box_pack_end(app_mem->box, app_mem->entry[i]); + + evas_object_size_hint_align_set(app_mem->btn[i], EVAS_HINT_FILL, EVAS_HINT_FILL); + evas_object_size_hint_align_set(app_mem->entry[i], EVAS_HINT_FILL, EVAS_HINT_FILL); + + evas_object_show(app_mem->btn[i]); + evas_object_show(app_mem->entry[i]); + } + + elm_object_text_set(app_mem->entry[BUTTON_MEM_APPLY_MEM],"Texture limit in MB"); + elm_object_text_set(app_mem->entry[BUTTON_MEM_APPLY_FONT_SIZE],"20"); + + evas_object_size_hint_weight_set(app_mem->main_entry, EVAS_HINT_EXPAND,EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(app_mem->main_entry, EVAS_HINT_FILL, EVAS_HINT_FILL); + + evas_object_show(app_mem->win); +} + /*** Label Wrap **************************************************************/ void test_label_wrap(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) diff --git a/src/lib/evas/Evas_Common.h b/src/lib/evas/Evas_Common.h index 97a5e1adb4..e365eb9f0d 100644 --- a/src/lib/evas/Evas_Common.h +++ b/src/lib/evas/Evas_Common.h @@ -385,6 +385,12 @@ typedef Efl_Text_Bidirectional_Type Evas_BiDi_Direction; #define EVAS_BIDI_DIRECTION_RTL EFL_TEXT_BIDIRECTIONAL_TYPE_RTL #define EVAS_BIDI_DIRECTION_INHERIT EFL_TEXT_BIDIRECTIONAL_TYPE_INHERIT +typedef enum _Evas_Font_Data_Cache +{ + EVAS_FONT_DATA_CACHE_TEXTURE = 0x01,/**< Texture caching (in case of accelerated rendering) */ +} Evas_Font_Data_Cache; /**< font caching options, used for evas_font_data_cache_set()/evas_font_data_cache_get()*/ + + /** * How the mouse pointer should be handled by Evas. * @@ -3370,6 +3376,33 @@ EAPI const Eina_List *evas_font_path_global_list(void) EINA_WARN_UNUSED_R */ EAPI void evas_font_reinit(void); +/** + * @} + */ + +#define EVAS_FONT_DATA_CACHE_TEXTURE 0x01 + +/** + * Set the limit in bytes for memory allocated by font glyphs in evas. + * @param[in] options for caching. + * @param[in] bytes cache size in bytes, pass negative value to ignore the limit. + * + * @since 1.24 + */ +EAPI void evas_font_data_cache_set(Evas_Font_Data_Cache options, int byte); + +/** + * @} + */ + +/** + * Get the limit in bytes for memory allocated by font glyphs in evas. + * @param[in] options for caching. + * @return Returns font allocated memory cache limit, if value is negative this means no limit. + * @since 1.24 + */ +EAPI int evas_font_data_cache_get(Evas_Font_Data_Cache options); + /** * @} */ diff --git a/src/lib/evas/canvas/evas_render.c b/src/lib/evas/canvas/evas_render.c index c33f69a22d..cac56d1757 100644 --- a/src/lib/evas/canvas/evas_render.c +++ b/src/lib/evas/canvas/evas_render.c @@ -3713,6 +3713,11 @@ evas_render_updates_internal(Evas *eo_e, } eina_evlog("-render_phase8", eo_e, 0.0, NULL); + if (evas_font_data_cache_get(EVAS_FONT_DATA_CACHE_TEXTURE) == 0) + ENFN->font_glyphs_gc_collect(ENC, 1.0f, NULL, NULL, EINA_TRUE); + else + ENFN->font_glyphs_gc_collect(ENC, 0.33f, NULL, NULL, EINA_TRUE); + eina_evlog("+render_clear", eo_e, 0.0, NULL); if (!do_async && rendering) { diff --git a/src/lib/evas/common/evas_font_main.c b/src/lib/evas/common/evas_font_main.c index 3a5b280437..50de0819bc 100644 --- a/src/lib/evas/common/evas_font_main.c +++ b/src/lib/evas/common/evas_font_main.c @@ -13,7 +13,8 @@ LK(lock_font_draw); // for freetype2 API calls LK(lock_bidi); // for evas bidi internal usage. LK(lock_ot); // for evas bidi internal usage. -int _evas_font_log_dom_global = -1; +int _evas_font_log_dom_global = -1; +int _evas_font_texture_cache = -1; EAPI void evas_common_font_init(void) @@ -854,6 +855,25 @@ evas_common_font_int_cache_glyph_get(RGBA_Font_Int *fi, FT_UInt idx) return fg; } +EAPI void +evas_font_data_cache_set(Evas_Font_Data_Cache options, int bytes) +{ + if ((options & EVAS_FONT_DATA_CACHE_TEXTURE) == EVAS_FONT_DATA_CACHE_TEXTURE) + { + _evas_font_texture_cache = bytes; + //FIXME No direct free happend until next render call + } +} + +EAPI int +evas_font_data_cache_get(Evas_Font_Data_Cache options) +{ + if ((options & EVAS_FONT_DATA_CACHE_TEXTURE) == EVAS_FONT_DATA_CACHE_TEXTURE) + return _evas_font_texture_cache; + else + return -1; +} + EAPI Eina_Bool evas_common_font_int_cache_glyph_render(RGBA_Font_Glyph *fg) { diff --git a/src/lib/evas/include/evas_common_private.h b/src/lib/evas/include/evas_common_private.h index 509f7c93a8..e4a5168bdb 100644 --- a/src/lib/evas/include/evas_common_private.h +++ b/src/lib/evas/include/evas_common_private.h @@ -691,6 +691,7 @@ struct _RGBA_Draw_Context void *(*gl_image_new) (void *gc, RGBA_Font_Glyph *fg, int alpha, Evas_Colorspace cspace); void (*gl_image_free) (void *image); void (*gl_image_draw) (void *gc, void *im, int dx, int dy, int dw, int dh, int smooth); + void (*gl_garbage_collector) (void *gc, float ratio, int *texture_size, int *atlas_size); } func; void *data; } font_ext; diff --git a/src/lib/evas/include/evas_private.h b/src/lib/evas/include/evas_private.h index 147e2ae0d1..d270b2be65 100644 --- a/src/lib/evas/include/evas_private.h +++ b/src/lib/evas/include/evas_private.h @@ -1103,6 +1103,8 @@ struct _Evas_Func Evas_Filter_Support (*gfx_filter_supports) (void *engine, Evas_Filter_Command *cmd); Eina_Bool (*gfx_filter_process) (void *engine, Evas_Filter_Command *cmd); + void (*font_glyphs_gc_collect) (void *engine, float ratio, int *texture_size, int *atlas_size, Eina_Bool only_when_requested); + unsigned int info_size; }; diff --git a/src/modules/evas/engines/gl_common/evas_gl_common.h b/src/modules/evas/engines/gl_common/evas_gl_common.h index 5873b93fb6..c7b4d22150 100644 --- a/src/modules/evas/engines/gl_common/evas_gl_common.h +++ b/src/modules/evas/engines/gl_common/evas_gl_common.h @@ -368,6 +368,9 @@ struct _Evas_Engine_GL_Context Eina_List *font_glyph_images; Evas_GL_Image *def_surface; RGBA_Image *font_surface; + int font_glyph_textures_size; + int font_glyph_atlas_size; + Eina_Bool font_glyph_gc_requested :1; #ifdef GL_GLES // FIXME: hack. expose egl display to gl core for egl image sec extn. diff --git a/src/modules/evas/engines/gl_common/evas_gl_font.c b/src/modules/evas/engines/gl_common/evas_gl_font.c index 53260d971d..4a5f428487 100644 --- a/src/modules/evas/engines/gl_common/evas_gl_font.c +++ b/src/modules/evas/engines/gl_common/evas_gl_font.c @@ -218,13 +218,37 @@ void evas_gl_font_image_draw(void *gc, void *gl_image, int dx, int dy, int dw, int dh, int smooth) { Evas_GL_Image *im = (Evas_GL_Image *)gl_image; + Evas_Engine_GL_Context *gl_context = gc; + Eina_Bool is_cached = EINA_FALSE; + Eina_Bool is_new_atlas = EINA_FALSE; if (!im || !im->fglyph) return; - evas_gl_common_image_draw((Evas_Engine_GL_Context *)gc, + is_cached = (im->tex != NULL) && (im->tex->pt != NULL); + + evas_gl_common_image_draw(gl_context, im, 0, 0, (unsigned int)im->fglyph->glyph_out->bitmap.width, (unsigned int)im->fglyph->glyph_out->bitmap.rows, dx, dy, dw, dh, smooth); + + // Move latest used glyph image to the back, because GC will start freeing from the beginning + gl_context->font_glyph_images = eina_list_remove(gl_context->font_glyph_images, im); + gl_context->font_glyph_images = eina_list_append(gl_context->font_glyph_images, im); + + if (!is_cached) + { + gl_context->font_glyph_textures_size += im->w * im->h * 4; + } + + is_new_atlas = (!is_cached) && (im->tex != NULL) && (im->tex->pt) && (im->tex->pt->references == 1); + if (is_new_atlas) + { + int size = (im->tex->pt->w * im->tex->pt->h * 4); + gl_context->font_glyph_atlas_size += size; + if ((evas_font_data_cache_get(EVAS_FONT_DATA_CACHE_TEXTURE) >= 0) && + (evas_font_data_cache_get(EVAS_FONT_DATA_CACHE_TEXTURE) * 0.95 < gl_context->font_glyph_atlas_size)) + gl_context->font_glyph_gc_requested = EINA_TRUE; + } } diff --git a/src/modules/evas/engines/gl_common/evas_gl_texture.c b/src/modules/evas/engines/gl_common/evas_gl_texture.c index 1aa9d3ccb0..47dd8305a8 100644 --- a/src/modules/evas/engines/gl_common/evas_gl_texture.c +++ b/src/modules/evas/engines/gl_common/evas_gl_texture.c @@ -1565,6 +1565,7 @@ evas_gl_common_texture_free(Evas_GL_Texture *tex, Eina_Bool force) if (tex->references != 0) return; if (tex->fglyph) { + tex->gc->font_glyph_textures_size -= tex->w * tex->h * 4; tex->gc->font_glyph_textures = eina_list_remove(tex->gc->font_glyph_textures, tex); tex->fglyph->ext_dat = NULL; tex->fglyph->ext_dat_free = NULL; @@ -1575,6 +1576,10 @@ evas_gl_common_texture_free(Evas_GL_Texture *tex, Eina_Bool force) tex->pt->allocations = eina_list_remove(tex->pt->allocations, tex->apt); if (tex->apt) eina_rectangle_pool_release(tex->apt); tex->apt = NULL; + if (tex->fglyph && (tex->pt->references == 1)) + { + tex->gc->font_glyph_atlas_size -= tex->pt->w * tex->pt->h * 4; + } pt_unref(tex->pt); tex->pt = NULL; } diff --git a/src/modules/evas/engines/gl_generic/evas_engine.c b/src/modules/evas/engines/gl_generic/evas_engine.c index 0fc241643d..a051f00242 100644 --- a/src/modules/evas/engines/gl_generic/evas_engine.c +++ b/src/modules/evas/engines/gl_generic/evas_engine.c @@ -3023,6 +3023,42 @@ eng_gfx_filter_process(void *engine, Evas_Filter_Command *cmd) return pfunc.gfx_filter_process(&re->software, cmd); } +static void +eng_font_glyphs_gc_collect(void *data EINA_UNUSED, float ratio EINA_UNUSED, int *texture_size EINA_UNUSED, int *atlas_size EINA_UNUSED, Eina_Bool only_when_requested EINA_UNUSED) +{ + Evas_Engine_GL_Context *gl_context; + gl_context = gl_generic_context_find(data, 1); + + if ((only_when_requested && gl_context->font_glyph_gc_requested) || (!only_when_requested)) + { + if (ratio > 0.0) + { + int requested_size = ratio * gl_context->font_glyph_textures_size; + + Eina_List *l; + Eina_List *ll; + Evas_GL_Image *im; + EINA_LIST_FOREACH_SAFE(gl_context->font_glyph_images, l, ll, im) + { + int size = im->w * im->h * 4; + gl_context->font_glyph_textures_size -= size; + requested_size -= size; + if ((im->tex != NULL) && (im->tex->pt) && (im->tex->pt->references == 1)) + { + gl_context->font_glyph_atlas_size -= im->tex->pt->w * im->tex->pt->h * 4; + } + evas_gl_common_image_free(im); + if (requested_size <= 0) + break; + } + } + + gl_context->font_glyph_gc_requested = EINA_FALSE; + } + if (texture_size) *texture_size = gl_context->font_glyph_textures_size; + if (atlas_size) *atlas_size = gl_context->font_glyph_atlas_size; +} + //------------------------------------------------// static int @@ -3178,6 +3214,7 @@ module_open(Evas_Module *em) ORD(ector_surface_cache_drop); ORD(gfx_filter_supports); ORD(gfx_filter_process); + ORD(font_glyphs_gc_collect); /* now advertise out own api */ em->functions = (void *)(&func); diff --git a/src/modules/evas/engines/software_generic/evas_engine.c b/src/modules/evas/engines/software_generic/evas_engine.c index a942a96f02..aca24c4936 100644 --- a/src/modules/evas/engines/software_generic/evas_engine.c +++ b/src/modules/evas/engines/software_generic/evas_engine.c @@ -4645,6 +4645,12 @@ eng_gfx_filter_supports(void *data EINA_UNUSED, Evas_Filter_Command *cmd) return EVAS_FILTER_SUPPORT_CPU; } +static void +eng_font_glyphs_gc_collect(void *data EINA_UNUSED, float ratio EINA_UNUSED, int *texture_size EINA_UNUSED, int *atlas_size EINA_UNUSED, Eina_Bool only_when_requested EINA_UNUSED) +{ + return; +} + static Eina_Bool eng_gfx_filter_process(void *data EINA_UNUSED, Evas_Filter_Command *cmd) { @@ -4851,6 +4857,7 @@ static Evas_Func func = eng_gfx_filter_supports, eng_gfx_filter_process, /* FUTURE software generic calls go here */ + eng_font_glyphs_gc_collect, 0 // sizeof (Info) }; --