From 5fc66822b93212582db13287ba5aaf2f219f6837 Mon Sep 17 00:00:00 2001 From: Gabor Kiss-Vamosi Date: Thu, 10 Dec 2020 11:14:22 +0100 Subject: [PATCH] feat(img_cache): allow disabling image cacheing related to #1954 --- CHANGELOG.md | 1 + lv_conf_template.h | 2 +- src/lv_core/lv_obj.c | 3 +- src/lv_draw/lv_draw_img.c | 21 ++++++-- src/lv_draw/lv_img_cache.c | 104 +++++++++++++++++++++---------------- 5 files changed, 79 insertions(+), 52 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0464f3306..98f155cd0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ ### New features - feat(chart) add lv_chart_remove_series and lv_chart_hide_series +- feat(img_cahce) allow disabling image cacheing ### Bugfixes diff --git a/lv_conf_template.h b/lv_conf_template.h index ec423dfaf..fddd29882 100644 --- a/lv_conf_template.h +++ b/lv_conf_template.h @@ -240,7 +240,7 @@ typedef void * lv_fs_drv_user_data_t; * (I.e. no new image decoder is added) * With complex image decoders (e.g. PNG or JPG) caching can save the continuous open/decode of images. * However the opened images might consume additional RAM. - * LV_IMG_CACHE_DEF_SIZE must be >= 1 */ + * Set it to 0 to disable caching */ #define LV_IMG_CACHE_DEF_SIZE 1 /*Declare the type of the user data of image decoder (can be e.g. `void *`, `int`, `struct`)*/ diff --git a/src/lv_core/lv_obj.c b/src/lv_core/lv_obj.c index c73d58e3f..d962144d3 100644 --- a/src/lv_core/lv_obj.c +++ b/src/lv_core/lv_obj.c @@ -221,8 +221,9 @@ void lv_init(void) _lv_indev_init(); _lv_img_decoder_init(); +#if LV_IMG_CACHE_DEF_SIZE lv_img_cache_set_size(LV_IMG_CACHE_DEF_SIZE); - +#endif /*Test if the IDE has UTF-8 encoding*/ char * txt = "Á"; diff --git a/src/lv_draw/lv_draw_img.c b/src/lv_draw/lv_draw_img.c index 1e6de095f..2970fe43a 100644 --- a/src/lv_draw/lv_draw_img.c +++ b/src/lv_draw/lv_draw_img.c @@ -40,6 +40,7 @@ LV_ATTRIBUTE_FAST_MEM static void lv_draw_map(const lv_area_t * map_area, const bool chroma_key, bool alpha_byte); static void show_error(const lv_area_t * coords, const lv_area_t * clip_area, const char * msg); +static void draw_cleanup(lv_img_cache_entry_t * cache); /********************** * STATIC VARIABLES @@ -267,9 +268,10 @@ LV_ATTRIBUTE_FAST_MEM static lv_res_t lv_img_draw_core(const lv_area_t * coords, lv_area_t mask_com; /*Common area of mask and coords*/ bool union_ok; union_ok = _lv_area_intersect(&mask_com, clip_area, &map_area_rot); + /*Out of mask. There is nothing to draw so the image is drawn successfully.*/ if(union_ok == false) { - return LV_RES_OK; /*Out of mask. There is nothing to draw so the image is drawn - successfully.*/ + draw_cleanup(cdsc); + return LV_RES_OK; } lv_draw_map(coords, &mask_com, cdsc->dec_dsc.img_data, draw_dsc, chroma_keyed, alpha_byte); @@ -279,9 +281,10 @@ LV_ATTRIBUTE_FAST_MEM static lv_res_t lv_img_draw_core(const lv_area_t * coords, lv_area_t mask_com; /*Common area of mask and coords*/ bool union_ok; union_ok = _lv_area_intersect(&mask_com, clip_area, coords); + /*Out of mask. There is nothing to draw so the image is drawn successfully.*/ if(union_ok == false) { - return LV_RES_OK; /*Out of mask. There is nothing to draw so the image is drawn - successfully.*/ + draw_cleanup(cdsc); + return LV_RES_OK; } int32_t width = lv_area_get_width(&mask_com); @@ -306,6 +309,7 @@ LV_ATTRIBUTE_FAST_MEM static lv_res_t lv_img_draw_core(const lv_area_t * coords, lv_img_decoder_close(&cdsc->dec_dsc); LV_LOG_WARN("Image draw can't read the line"); _lv_mem_buf_release(buf); + draw_cleanup(cdsc); return LV_RES_INV; } @@ -318,6 +322,7 @@ LV_ATTRIBUTE_FAST_MEM static lv_res_t lv_img_draw_core(const lv_area_t * coords, _lv_mem_buf_release(buf); } + draw_cleanup(cdsc); return LV_RES_OK; } @@ -649,3 +654,11 @@ static void show_error(const lv_area_t * coords, const lv_area_t * clip_area, co lv_draw_label(coords, clip_area, &label_dsc, msg, NULL); } +static void draw_cleanup(lv_img_cache_entry_t * cache) +{ +/*Automatically close images with no caching*/ +#if LV_IMG_CACHE_DEF_SIZE == 0 + lv_img_decoder_close(&cache->dec_dsc); +#endif +} + diff --git a/src/lv_draw/lv_img_cache.c b/src/lv_draw/lv_img_cache.c index cef32144f..2488865c3 100644 --- a/src/lv_draw/lv_img_cache.c +++ b/src/lv_draw/lv_img_cache.c @@ -19,7 +19,7 @@ /********************* * DEFINES *********************/ -/*Decrement life with this value in every open*/ +/*Decrement life with this value on every open*/ #define LV_IMG_CACHE_AGING 1 /*Boost life by this factor (multiply time_to_open with this value)*/ @@ -29,10 +29,6 @@ * "die" from very high values */ #define LV_IMG_CACHE_LIFE_LIMIT 1000 -#if LV_IMG_CACHE_DEF_SIZE < 1 - #error "LV_IMG_CACHE_DEF_SIZE must be >= 1. See lv_conf.h" -#endif - /********************** * TYPEDEFS **********************/ @@ -40,11 +36,16 @@ /********************** * STATIC PROTOTYPES **********************/ +#if LV_IMG_CACHE_DEF_SIZE == 0 +static lv_img_cache_entry_t cache_temp; +#endif /********************** * STATIC VARIABLES **********************/ +#if LV_IMG_CACHE_DEF_SIZE static uint16_t entry_cnt; +#endif /********************** * MACROS @@ -64,6 +65,10 @@ static uint16_t entry_cnt; */ lv_img_cache_entry_t * _lv_img_cache_open(const void * src, lv_color_t color) { + /*Is the image cached?*/ + lv_img_cache_entry_t * cached_src = NULL; + +#if LV_IMG_CACHE_DEF_SIZE if(entry_cnt == 0) { LV_LOG_WARN("lv_img_cache_open: the cache size is 0"); return NULL; @@ -79,8 +84,6 @@ lv_img_cache_entry_t * _lv_img_cache_open(const void * src, lv_color_t color) } } - /*Is the image cached?*/ - lv_img_cache_entry_t * cached_src = NULL; for(i = 0; i < entry_cnt; i++) { bool match = false; lv_img_src_t src_type = lv_img_src_get_type(cache[i].dec_dsc.src); @@ -104,48 +107,51 @@ lv_img_cache_entry_t * _lv_img_cache_open(const void * src, lv_color_t color) } /*The image is not cached then cache it now*/ - if(cached_src == NULL) { - /*Find an entry to reuse. Select the entry with the least life*/ - cached_src = &cache[0]; - for(i = 1; i < entry_cnt; i++) { - if(cache[i].life < cached_src->life) { - cached_src = &cache[i]; - } - } + if(cached_src) return cached_src; - /*Close the decoder to reuse if it was opened (has a valid source)*/ - if(cached_src->dec_dsc.src) { - lv_img_decoder_close(&cached_src->dec_dsc); - LV_LOG_INFO("image draw: cache miss, close and reuse an entry"); + /*Find an entry to reuse. Select the entry with the least life*/ + cached_src = &cache[0]; + for(i = 1; i < entry_cnt; i++) { + if(cache[i].life < cached_src->life) { + cached_src = &cache[i]; } - else { - LV_LOG_INFO("image draw: cache miss, cached to an empty entry"); - } - - /*Open the image and measure the time to open*/ - uint32_t t_start; - t_start = lv_tick_get(); - cached_src->dec_dsc.time_to_open = 0; - lv_res_t open_res = lv_img_decoder_open(&cached_src->dec_dsc, src, color); - if(open_res == LV_RES_INV) { - LV_LOG_WARN("Image draw cannot open the image resource"); - lv_img_decoder_close(&cached_src->dec_dsc); - _lv_memset_00(&cached_src->dec_dsc, sizeof(lv_img_decoder_dsc_t)); - _lv_memset_00(cached_src, sizeof(lv_img_cache_entry_t)); - cached_src->life = INT32_MIN; /*Make the empty entry very "weak" to force its use */ - return NULL; - } - - cached_src->life = 0; - - /*If `time_to_open` was not set in the open function set it here*/ - if(cached_src->dec_dsc.time_to_open == 0) { - cached_src->dec_dsc.time_to_open = lv_tick_elaps(t_start); - } - - if(cached_src->dec_dsc.time_to_open == 0) cached_src->dec_dsc.time_to_open = 1; } + /*Close the decoder to reuse if it was opened (has a valid source)*/ + if(cached_src->dec_dsc.src) { + lv_img_decoder_close(&cached_src->dec_dsc); + LV_LOG_INFO("image draw: cache miss, close and reuse an entry"); + } + else { + LV_LOG_INFO("image draw: cache miss, cached to an empty entry"); + } + +#else + cached_src = &cache_temp; +#endif + /*Open the image and measure the time to open*/ + uint32_t t_start; + t_start = lv_tick_get(); + cached_src->dec_dsc.time_to_open = 0; + lv_res_t open_res = lv_img_decoder_open(&cached_src->dec_dsc, src, color); + if(open_res == LV_RES_INV) { + LV_LOG_WARN("Image draw cannot open the image resource"); + lv_img_decoder_close(&cached_src->dec_dsc); + _lv_memset_00(&cached_src->dec_dsc, sizeof(lv_img_decoder_dsc_t)); + _lv_memset_00(cached_src, sizeof(lv_img_cache_entry_t)); + cached_src->life = INT32_MIN; /*Make the empty entry very "weak" to force its use */ + return NULL; + } + + cached_src->life = 0; + + /*If `time_to_open` was not set in the open function set it here*/ + if(cached_src->dec_dsc.time_to_open == 0) { + cached_src->dec_dsc.time_to_open = lv_tick_elaps(t_start); + } + + if(cached_src->dec_dsc.time_to_open == 0) cached_src->dec_dsc.time_to_open = 1; + return cached_src; } @@ -157,6 +163,10 @@ lv_img_cache_entry_t * _lv_img_cache_open(const void * src, lv_color_t color) */ void lv_img_cache_set_size(uint16_t new_entry_cnt) { +#if LV_IMG_CACHE_DEF_SIZE == 0 + LV_UNUSED(new_entry_cnt); + LV_LOG_WARN("Can't change cache size because it's disabled by LV_IMG_CACHE_DEF_SIZE = 0"); +#else if(LV_GC_ROOT(_lv_img_cache_array) != NULL) { /*Clean the cache before free it*/ lv_img_cache_invalidate_src(NULL); @@ -178,6 +188,7 @@ void lv_img_cache_set_size(uint16_t new_entry_cnt) _lv_memset_00(&LV_GC_ROOT(_lv_img_cache_array)[i].dec_dsc, sizeof(lv_img_decoder_dsc_t)); _lv_memset_00(&LV_GC_ROOT(_lv_img_cache_array)[i], sizeof(lv_img_cache_entry_t)); } +#endif } /** @@ -187,7 +198,7 @@ void lv_img_cache_set_size(uint16_t new_entry_cnt) */ void lv_img_cache_invalidate_src(const void * src) { - +#if LV_IMG_CACHE_DEF_SIZE lv_img_cache_entry_t * cache = LV_GC_ROOT(_lv_img_cache_array); uint16_t i; @@ -201,6 +212,7 @@ void lv_img_cache_invalidate_src(const void * src) _lv_memset_00(&cache[i], sizeof(lv_img_cache_entry_t)); } } +#endif } /**********************