diff --git a/lv_conf_template.h b/lv_conf_template.h index da57a63aa..d6a84bc73 100644 --- a/lv_conf_template.h +++ b/lv_conf_template.h @@ -247,13 +247,11 @@ #define LV_GLOBAL_CUSTOM_INCLUDE #endif -/*Default image cache size. Image caching keeps some images opened. - *If only the built-in image formats are used there is no real advantage of caching. - *With other image decoders (e.g. PNG or JPG) caching save the continuous open/decode of images. - *However the opened images consume additional RAM. - *0: to disable caching*/ -#define LV_IMAGE_CACHE_DEF_SIZE 0 - +/*Default cache size in bytes. + *Used by image decoders such as `lv_png` to keep the decoded image in the memory. + *Data larger than the size of the cache also can be allocated but + *will be dropped immediately after usage.*/ +#define LV_CACHE_DEF_SIZE 0 /*Number of stops allowed per gradient. Increase this to allow more stops. *This adds (sizeof(lv_color_t) + 1) bytes per additional stop*/ diff --git a/src/core/lv_global.h b/src/core/lv_global.h index ced447f35..c853b4b15 100644 --- a/src/core/lv_global.h +++ b/src/core/lv_global.h @@ -17,7 +17,8 @@ extern "C" { #include -#include "../draw/lv_image_cache.h" +#include "../misc/lv_cache.h" +#include "../misc/lv_cache_builtin.h" #include "../draw/lv_draw.h" #if LV_USE_DRAW_SW #include "../draw/sw/lv_draw_sw.h" @@ -101,13 +102,9 @@ typedef struct _lv_global_t { lv_draw_buf_handlers_t draw_buf_handlers; lv_ll_t img_decoder_ll; - lv_image_cache_manager_t img_cache_mgr; -#if LV_IMAGE_CACHE_DEF_SIZE - uint16_t img_cache_entry_cnt; - _lv_image_cache_entry_t * img_cache_array; -#else - _lv_image_cache_entry_t img_cache_single; -#endif + lv_cache_manager_t cache_manager; + lv_cache_builtin_dsc_t cache_builtin_dsc; + size_t cache_builtin_max_size; lv_draw_global_info_t draw_info; #if defined(LV_DRAW_SW_SHADOW_CACHE_SIZE) && LV_DRAW_SW_SHADOW_CACHE_SIZE > 0 diff --git a/src/draw/lv_draw.h b/src/draw/lv_draw.h index 4be17ca88..eecdd37db 100644 --- a/src/draw/lv_draw.h +++ b/src/draw/lv_draw.h @@ -18,8 +18,8 @@ extern "C" { #include "../misc/lv_style.h" #include "../misc/lv_txt.h" #include "../misc/lv_profiler.h" +#include "../misc/lv_cache.h" #include "lv_image_decoder.h" -#include "lv_image_cache.h" #include "../osal/lv_os.h" #include "lv_draw_buf.h" @@ -170,10 +170,10 @@ typedef struct { uint32_t used_memory_for_layers_kb; #if LV_USE_OS lv_thread_sync_t sync; - lv_mutex_t circle_cache_mutex; #else int dispatch_req; #endif + lv_mutex_t circle_cache_mutex; bool task_running; } lv_draw_global_info_t; diff --git a/src/draw/lv_draw_image.c b/src/draw/lv_draw_image.c index 77f661ae2..814c296d6 100644 --- a/src/draw/lv_draw_image.c +++ b/src/draw/lv_draw_image.c @@ -7,7 +7,6 @@ * INCLUDES *********************/ #include "lv_draw_image.h" -#include "lv_image_cache.h" #include "../disp/lv_disp.h" #include "../misc/lv_log.h" #include "../misc/lv_math.h" diff --git a/src/draw/lv_image_cache.c b/src/draw/lv_image_cache.c deleted file mode 100644 index ccf9cb4d7..000000000 --- a/src/draw/lv_image_cache.c +++ /dev/null @@ -1,70 +0,0 @@ -/** - * @file lv_image_cache.c - * - */ - -/********************* - * INCLUDES - *********************/ -#include "lv_image_cache.h" -#include "../stdlib/lv_string.h" -#include "../core/lv_global.h" - -/********************* - * DEFINES - *********************/ -#define img_cache_manager LV_GLOBAL_DEFAULT()->img_cache_mgr - -/********************** - * TYPEDEFS - **********************/ - -/********************** - * STATIC PROTOTYPES - **********************/ - -/********************** - * STATIC VARIABLES - **********************/ - -/********************** - * MACROS - **********************/ - -/********************** - * GLOBAL FUNCTIONS - **********************/ - -void lv_image_cache_manager_init(lv_image_cache_manager_t * manager) -{ - LV_ASSERT_NULL(manager); - lv_memzero(manager, sizeof(lv_image_cache_manager_t)); -} - -void lv_image_cache_manager_apply(const lv_image_cache_manager_t * manager) -{ - LV_ASSERT_NULL(manager); - lv_memcpy(&img_cache_manager, manager, sizeof(lv_image_cache_manager_t)); -} - -_lv_image_cache_entry_t * _lv_image_cache_open(const void * src, lv_color_t color, int32_t frame_id) -{ - LV_ASSERT_NULL(img_cache_manager.open_cb); - return img_cache_manager.open_cb(src, color, frame_id); -} - -void lv_image_cache_set_size(uint16_t new_entry_cnt) -{ - LV_ASSERT_NULL(img_cache_manager.set_size_cb); - img_cache_manager.set_size_cb(new_entry_cnt); -} - -void lv_image_cache_invalidate_src(const void * src) -{ - LV_ASSERT_NULL(img_cache_manager.invalidate_src_cb); - img_cache_manager.invalidate_src_cb(src); -} - -/********************** - * STATIC FUNCTIONS - **********************/ diff --git a/src/draw/lv_image_cache.h b/src/draw/lv_image_cache.h deleted file mode 100644 index 40ebdd7de..000000000 --- a/src/draw/lv_image_cache.h +++ /dev/null @@ -1,92 +0,0 @@ -/** - * @file lv_image_cache.h - * - */ - -#ifndef LV_IMAGE_CACHE_H -#define LV_IMAGE_CACHE_H - -#ifdef __cplusplus -extern "C" { -#endif - -/********************* - * INCLUDES - *********************/ -#include "lv_image_decoder.h" - -/********************* - * DEFINES - *********************/ - -/********************** - * TYPEDEFS - **********************/ - -/** - * When loading images from the network it can take a long time to download and decode the image. - * - * To avoid repeating this heavy load images can be cached. - */ -typedef struct { - lv_image_decoder_dsc_t dec_dsc; /**< Image information*/ - void * user_data; /**< Image cache entry user data*/ -} _lv_image_cache_entry_t; - -typedef struct { - _lv_image_cache_entry_t * (*open_cb)(const void * src, lv_color_t color, int32_t frame_id); - void (*set_size_cb)(uint16_t new_entry_cnt); - void (*invalidate_src_cb)(const void * src); -} lv_image_cache_manager_t; - -/********************** - * GLOBAL PROTOTYPES - **********************/ - -/** - * Initialize the img cache manager - * @param manager Pointer to the img cache manager - */ -void lv_image_cache_manager_init(lv_image_cache_manager_t * manager); - -/** - * Apply the img cache manager - * @param manager Pointer to the img cache manager - */ -void lv_image_cache_manager_apply(const lv_image_cache_manager_t * manager); - -/** - * Open an image using the image decoder interface and cache it. - * The image will be left open meaning if the image decoder open callback allocated memory then it will remain. - * The image is closed if a new image is opened and the new image takes its place in the cache. - * @param src source of the image. Path to file or pointer to an `lv_image_dsc_t` variable - * @param color The color of the image with `LV_IMAGE_CF_ALPHA_...` - * @param frame_id the index of the frame. Used only with animated images, set 0 for normal images - * @return pointer to the cache entry or NULL if can open the image - */ -_lv_image_cache_entry_t * _lv_image_cache_open(const void * src, lv_color_t color, int32_t frame_id); - -/** - * Set the number of images to be cached. - * More cached images mean more opened image at same time which might mean more memory usage. - * E.g. if 20 PNG or JPG images are open in the RAM they consume memory while opened in the cache. - * @param new_entry_cnt number of image to cache - */ -void lv_image_cache_set_size(uint16_t new_entry_cnt); - -/** - * Invalidate an image source in the cache. - * Useful if the image source is updated therefore it needs to be cached again. - * @param src an image source path to a file or pointer to an `lv_image_dsc_t` variable. - */ -void lv_image_cache_invalidate_src(const void * src); - -/********************** - * MACROS - **********************/ - -#ifdef __cplusplus -} /*extern "C"*/ -#endif - -#endif /*LV_IMAGE_CACHE_H*/ diff --git a/src/draw/lv_image_cache_builtin.c b/src/draw/lv_image_cache_builtin.c deleted file mode 100644 index e7fb297ac..000000000 --- a/src/draw/lv_image_cache_builtin.c +++ /dev/null @@ -1,249 +0,0 @@ -/** - * @file lv_image_cache_builtin.c - * - */ - -/********************* - * INCLUDES - *********************/ -#include "lv_image_cache.h" -#include "lv_image_cache_builtin.h" -#include "lv_image_decoder.h" -#include "lv_draw_image.h" -#include "../tick/lv_tick.h" -#include "../misc/lv_assert.h" -#include "../core/lv_global.h" -#include "../stdlib/lv_string.h" - -/********************* - * DEFINES - *********************/ -#if LV_IMAGE_CACHE_DEF_SIZE - #define entry_cnt LV_GLOBAL_DEFAULT()->img_cache_entry_cnt - #define _image_cache_array LV_GLOBAL_DEFAULT()->img_cache_array -#else - #define _image_cache_single LV_GLOBAL_DEFAULT()->img_cache_single -#endif - - -/** Count the cache entries's life. Add `time_to_open` to `life` when the entry is used. - * Decrement all lifes by one every in every ::lv_image_cache_open. - * If life == 0 the entry can be reused*/ -#define CACHE_GET_LIFE(entry) ((lv_intptr_t)((entry)->user_data)) -#define CACHE_SET_LIFE(entry, v) ((entry)->user_data = (void*)((lv_intptr_t)(v))) - -/*Decrement life with this value on every open*/ -#define LV_IMAGE_CACHE_AGING 1 - -/*Boost life by this factor (multiply time_to_open with this value)*/ -#define LV_IMAGE_CACHE_LIFE_GAIN 1 - -/*Don't let life to be greater than this limit because it would require a lot of time to - * "die" from very high values*/ -#define LV_IMAGE_CACHE_LIFE_LIMIT 1000 - -/********************** - * TYPEDEFS - **********************/ - -/********************** - * STATIC PROTOTYPES - **********************/ - -static _lv_image_cache_entry_t * _lv_image_cache_open_builtin(const void * src, lv_color_t color, int32_t frame_id); -static void lv_image_cache_set_size_builtin(uint16_t new_entry_cnt); -static void lv_image_cache_invalidate_src_builtin(const void * src); - -#if LV_IMAGE_CACHE_DEF_SIZE - static bool lv_image_cache_match(const void * src1, const void * src2); -#endif - -/********************** - * STATIC VARIABLES - **********************/ - -/********************** - * MACROS - **********************/ - -/********************** - * GLOBAL FUNCTIONS - **********************/ - -void _lv_image_cache_builtin_init(void) -{ -#if LV_IMAGE_CACHE_DEF_SIZE - lv_image_cache_set_size_builtin(LV_IMAGE_CACHE_DEF_SIZE); -#endif - - lv_image_cache_manager_t manager; - lv_image_cache_manager_init(&manager); - manager.open_cb = _lv_image_cache_open_builtin; - manager.set_size_cb = lv_image_cache_set_size_builtin; - manager.invalidate_src_cb = lv_image_cache_invalidate_src_builtin; - lv_image_cache_manager_apply(&manager); -} - -/********************** - * STATIC FUNCTIONS - **********************/ - -/** - * Open an image using the image decoder interface and cache it. - * The image will be left open meaning if the image decoder open callback allocated memory then it will remain. - * The image is closed if a new image is opened and the new image takes its place in the cache. - * @param src source of the image. Path to file or pointer to an `lv_image_dsc_t` variable - * @param color color The color of the image with `LV_IMAGE_CF_ALPHA_...` - * @return pointer to the cache entry or NULL if can open the image - */ -static _lv_image_cache_entry_t * _lv_image_cache_open_builtin(const void * src, lv_color_t color, int32_t frame_id) -{ - /*Is the image cached?*/ - _lv_image_cache_entry_t * cached_src = NULL; - -#if LV_IMAGE_CACHE_DEF_SIZE - if(entry_cnt == 0) { - LV_LOG_WARN("the cache size is 0"); - return NULL; - } - - _lv_image_cache_entry_t * cache = _image_cache_array; - - /*Decrement all lifes. Make the entries older*/ - uint16_t i; - for(i = 0; i < entry_cnt; i++) { - int32_t life = CACHE_GET_LIFE(&cache[i]); - if(life > INT32_MIN + LV_IMAGE_CACHE_AGING) { - CACHE_SET_LIFE(&cache[i], life - LV_IMAGE_CACHE_AGING); - } - } - - for(i = 0; i < entry_cnt; i++) { - if(lv_color_eq(color, cache[i].dec_dsc.color) && - frame_id == cache[i].dec_dsc.frame_id && - lv_image_cache_match(src, cache[i].dec_dsc.src)) { - /*If opened increment its life. - *Image difficult to open should live longer to keep avoid frequent their recaching. - *Therefore increase `life` with `time_to_open`*/ - cached_src = &cache[i]; - int32_t life = CACHE_GET_LIFE(cached_src); - CACHE_SET_LIFE(cached_src, life + cached_src->dec_dsc.time_to_open * LV_IMAGE_CACHE_LIFE_GAIN); - if(CACHE_GET_LIFE(cached_src) > LV_IMAGE_CACHE_LIFE_LIMIT) CACHE_SET_LIFE(cached_src, LV_IMAGE_CACHE_LIFE_LIMIT); - LV_LOG_TRACE("image source found in the cache"); - break; - } - } - - /*The image is not cached then cache it now*/ - if(cached_src) return cached_src; - - /*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_GET_LIFE(&cache[i]) < CACHE_GET_LIFE(cached_src)) { - cached_src = &cache[i]; - } - } - - /*Close the decoder to reuse if it was opened (has a valid source)*/ - if(cached_src->dec_dsc.src) { - lv_image_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 = &(_image_cache_single); -#endif - /*Open the image and measure the time to open*/ - uint32_t t_start = lv_tick_get(); - lv_res_t open_res = lv_image_decoder_open(&cached_src->dec_dsc, src, color, frame_id); - if(open_res == LV_RES_INV) { - LV_LOG_WARN("Image draw cannot open the image resource"); - lv_memzero(cached_src, sizeof(_lv_image_cache_entry_t)); - CACHE_SET_LIFE(cached_src, INT32_MIN); /*Make the empty entry very "weak" to force its us*/ - return NULL; - } - - CACHE_SET_LIFE(cached_src, 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; -} - -/** - * Set the number of images to be cached. - * More cached images mean more opened image at same time which might mean more memory usage. - * E.g. if 20 PNG or JPG images are open in the RAM they consume memory while opened in the cache. - * @param new_entry_cnt number of image to cache - */ -static void lv_image_cache_set_size_builtin(uint16_t new_entry_cnt) -{ -#if LV_IMAGE_CACHE_DEF_SIZE == 0 - LV_UNUSED(new_entry_cnt); - LV_LOG_WARN("Can't change cache size because it's disabled by LV_IMAGE_CACHE_DEF_SIZE = 0"); -#else - if(_image_cache_array != NULL) { - /*Clean the cache before free it*/ - lv_image_cache_invalidate_src_builtin(NULL); - lv_free(_image_cache_array); - } - - /*Reallocate the cache*/ - _image_cache_array = lv_malloc(sizeof(_lv_image_cache_entry_t) * new_entry_cnt); - LV_ASSERT_MALLOC(_image_cache_array); - if(_image_cache_array == NULL) { - entry_cnt = 0; - return; - } - entry_cnt = new_entry_cnt; - - /*Clean the cache*/ - lv_memzero(_image_cache_array, entry_cnt * sizeof(_lv_image_cache_entry_t)); -#endif -} - -/** - * Invalidate an image source in the cache. - * Useful if the image source is updated therefore it needs to be cached again. - * @param src an image source path to a file or pointer to an `lv_image_dsc_t` variable. - */ -static void lv_image_cache_invalidate_src_builtin(const void * src) -{ - LV_UNUSED(src); -#if LV_IMAGE_CACHE_DEF_SIZE - _lv_image_cache_entry_t * cache = _image_cache_array; - - uint16_t i; - for(i = 0; i < entry_cnt; i++) { - if(src == NULL || lv_image_cache_match(src, cache[i].dec_dsc.src)) { - if(cache[i].dec_dsc.src != NULL) { - lv_image_decoder_close(&cache[i].dec_dsc); - } - - lv_memzero(&cache[i], sizeof(_lv_image_cache_entry_t)); - } - } -#endif -} - -#if LV_IMAGE_CACHE_DEF_SIZE -static bool lv_image_cache_match(const void * src1, const void * src2) -{ - lv_image_src_t src_type = lv_image_src_get_type(src1); - if(src_type == LV_IMAGE_SRC_VARIABLE) - return src1 == src2; - if(src_type != LV_IMAGE_SRC_FILE) - return false; - if(lv_image_src_get_type(src2) != LV_IMAGE_SRC_FILE) - return false; - return strcmp(src1, src2) == 0; -} -#endif diff --git a/src/draw/sw/lv_draw_sw_img.c b/src/draw/sw/lv_draw_sw_img.c index e83dd25b2..40b5605c0 100644 --- a/src/draw/sw/lv_draw_sw_img.c +++ b/src/draw/sw/lv_draw_sw_img.c @@ -9,12 +9,12 @@ #include "lv_draw_sw.h" #if LV_USE_DRAW_SW -#include "../lv_image_cache.h" #include "../../disp/lv_disp.h" #include "../../disp/lv_disp_private.h" #include "../../misc/lv_log.h" #include "../../core/lv_refr.h" #include "../../stdlib/lv_mem.h" +#include "../../misc/lv_cache.h" #include "../../misc/lv_math.h" #include "../../misc/lv_color.h" #include "../../stdlib/lv_string.h" diff --git a/src/draw/sw/lv_draw_sw_mask.c b/src/draw/sw/lv_draw_sw_mask.c index bfb30dcea..b7715c614 100644 --- a/src/draw/sw/lv_draw_sw_mask.c +++ b/src/draw/sw/lv_draw_sw_mask.c @@ -20,12 +20,10 @@ /********************* * DEFINES *********************/ -#define CIRCLE_CACHE_LIFE_MAX 1000 -#define CIRCLE_CACHE_AGING(life, r) life = LV_MIN(life + (r < 16 ? 1 : (r >> 4)), 1000) -#if LV_USE_OS - #define circle_cache_mutex LV_GLOBAL_DEFAULT()->draw_info.circle_cache_mutex -#endif -#define _circle_cache LV_GLOBAL_DEFAULT()->sw_circle_cache +#define CIRCLE_CACHE_LIFE_MAX 1000 +#define CIRCLE_CACHE_AGING(life, r) life = LV_MIN(life + (r < 16 ? 1 : (r >> 4)), 1000) +#define circle_cache_mutex LV_GLOBAL_DEFAULT()->draw_info.circle_cache_mutex +#define _circle_cache LV_GLOBAL_DEFAULT()->sw_circle_cache /********************** * TYPEDEFS @@ -81,9 +79,7 @@ LV_ATTRIBUTE_FAST_MEM static inline lv_opa_t mask_mix(lv_opa_t mask_act, lv_opa_ void lv_draw_sw_mask_init(void) { -#if LV_USE_OS lv_mutex_init(&circle_cache_mutex); -#endif } @@ -115,10 +111,7 @@ LV_ATTRIBUTE_FAST_MEM lv_draw_sw_mask_res_t lv_draw_sw_mask_apply(void * masks[] */ void lv_draw_sw_mask_free_param(void * p) { - -#if LV_USE_OS lv_mutex_lock(&circle_cache_mutex); -#endif _lv_draw_sw_mask_common_dsc_t * pdsc = p; if(pdsc->type == LV_DRAW_SW_MASK_TYPE_RADIUS) { lv_draw_sw_mask_radius_param_t * radius_p = (lv_draw_sw_mask_radius_param_t *) p; @@ -133,9 +126,7 @@ void lv_draw_sw_mask_free_param(void * p) } } -#if LV_USE_OS lv_mutex_unlock(&circle_cache_mutex); -#endif } void _lv_draw_sw_mask_cleanup(void) @@ -362,9 +353,7 @@ void lv_draw_sw_mask_radius_init(lv_draw_sw_mask_radius_param_t * param, const l return; } -#if LV_USE_OS lv_mutex_lock(&circle_cache_mutex); -#endif uint32_t i; @@ -374,9 +363,7 @@ void lv_draw_sw_mask_radius_init(lv_draw_sw_mask_radius_param_t * param, const l _circle_cache[i].used_cnt++; CIRCLE_CACHE_AGING(_circle_cache[i].life, radius); param->circle = &(_circle_cache[i]); -#if LV_USE_OS lv_mutex_unlock(&circle_cache_mutex); -#endif return; } } @@ -406,9 +393,7 @@ void lv_draw_sw_mask_radius_init(lv_draw_sw_mask_radius_param_t * param, const l param->circle = entry; circ_calc_aa4(param->circle, radius); -#if LV_USE_OS lv_mutex_unlock(&circle_cache_mutex); -#endif } diff --git a/src/libs/barcode/lv_barcode.c b/src/libs/barcode/lv_barcode.c index c180503da..83e875c23 100644 --- a/src/libs/barcode/lv_barcode.c +++ b/src/libs/barcode/lv_barcode.c @@ -177,7 +177,9 @@ static void lv_barcode_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj LV_UNUSED(class_p); lv_image_dsc_t * img = lv_canvas_get_image(obj); - lv_image_cache_invalidate_src(img); + lv_cache_lock(); + lv_cache_invalidate(lv_cache_find(img, LV_CACHE_SRC_TYPE_PTR, 0, 0)); + lv_cache_unlock(); if(!img->data) { LV_LOG_INFO("canvas buffer is NULL"); diff --git a/src/libs/gif/lv_gif.c b/src/libs/gif/lv_gif.c index 0cf34962f..9e0f5aef7 100644 --- a/src/libs/gif/lv_gif.c +++ b/src/libs/gif/lv_gif.c @@ -61,7 +61,10 @@ void lv_gif_set_src(lv_obj_t * obj, const void * src) /*Close previous gif if any*/ if(gifobj->gif) { - lv_image_cache_invalidate_src(&gifobj->imgdsc); + lv_cache_lock(); + lv_cache_invalidate(lv_cache_find(lv_img_get_src(obj), LV_CACHE_SRC_TYPE_PTR, 0, 0)); + lv_cache_unlock(); + gd_close_gif(gifobj->gif); gifobj->gif = NULL; gifobj->imgdsc.data = NULL; @@ -122,7 +125,11 @@ static void lv_gif_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj) { LV_UNUSED(class_p); lv_gif_t * gifobj = (lv_gif_t *) obj; - lv_image_cache_invalidate_src(&gifobj->imgdsc); + + lv_cache_lock(); + lv_cache_invalidate(lv_cache_find(lv_img_get_src(obj), LV_CACHE_SRC_TYPE_PTR, 0, 0)); + lv_cache_unlock(); + if(gifobj->gif) gd_close_gif(gifobj->gif); lv_timer_del(gifobj->timer); @@ -147,7 +154,9 @@ static void next_frame_task_cb(lv_timer_t * t) gd_render_frame(gifobj->gif, (uint8_t *)gifobj->imgdsc.data); - lv_image_cache_invalidate_src(lv_image_get_src(obj)); + lv_cache_lock(); + lv_cache_invalidate(lv_cache_find(lv_img_get_src(obj), LV_CACHE_SRC_TYPE_PTR, 0, 0)); + lv_cache_unlock(); lv_obj_invalidate(obj); } diff --git a/src/libs/png/lodepng.c b/src/libs/png/lodepng.c index 4bb391f52..61b8f7204 100644 --- a/src/libs/png/lodepng.c +++ b/src/libs/png/lodepng.c @@ -5308,7 +5308,7 @@ static void decodeGeneric(unsigned char ** out, unsigned * w, unsigned * h, if(!state->error) { outsize = lodepng_get_raw_size(*w, *h, &state->info_png.color); - *out = (unsigned char *)lodepng_malloc(outsize); + *out = (unsigned char *)lv_draw_buf_malloc(outsize, LV_COLOR_FORMAT_ARGB8888); if(!*out) state->error = 83; /*alloc fail*/ } if(!state->error) { diff --git a/src/libs/png/lv_png.c b/src/libs/png/lv_png.c index 736086194..f74f66c33 100644 --- a/src/libs/png/lv_png.c +++ b/src/libs/png/lv_png.c @@ -28,6 +28,8 @@ static lv_res_t decoder_info(struct _lv_image_decoder_t * decoder, const void * static lv_res_t decoder_open(lv_image_decoder_t * dec, lv_image_decoder_dsc_t * dsc); static void decoder_close(lv_image_decoder_t * dec, lv_image_decoder_dsc_t * dsc); static void convert_color_depth(uint8_t * img_p, uint32_t px_cnt); +static const void * decode_png_data(const void * png_data, size_t png_data_size); +static lv_res_t try_cache(lv_image_decoder_dsc_t * dsc); /********************** * STATIC VARIABLES @@ -142,87 +144,129 @@ static lv_res_t decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_dsc_ { (void) decoder; /*Unused*/ - uint32_t error; /*For the return values of PNG decoder functions*/ - uint8_t * img_data = NULL; + /*Check the cache first*/ + if(try_cache(dsc) == LV_RES_OK) return LV_RES_OK; - /*If it's a PNG file...*/ + const uint8_t * png_data = NULL; + size_t png_data_size = 0; if(dsc->src_type == LV_IMAGE_SRC_FILE) { const char * fn = dsc->src; if(strcmp(lv_fs_get_ext(fn), "png") == 0) { /*Check the extension*/ - - /*Load the PNG file into buffer. It's still compressed (not decoded)*/ - unsigned char * png_data = NULL; /*Pointer to the loaded data. Same as the original file just loaded into the RAM*/ - size_t png_data_size; /*Size of `png_data` in bytes*/ - - error = lodepng_load_file(&png_data, &png_data_size, fn); /*Load the file*/ + unsigned error; + error = lodepng_load_file((void *)&png_data, &png_data_size, fn); /*Load the file*/ if(error) { if(png_data != NULL) { - lv_free(png_data); + lv_free((void *)png_data); } LV_LOG_WARN("error %" LV_PRIu32 ": %s\n", error, lodepng_error_text(error)); return LV_RES_INV; } - - /*Decode the PNG image*/ - unsigned png_width; /*Will be the width of the decoded image*/ - unsigned png_height; /*Will be the width of the decoded image*/ - - /*Decode the loaded image in ARGB8888 */ - error = lodepng_decode32(&img_data, &png_width, &png_height, png_data, png_data_size); - lv_free(png_data); /*Free the loaded file*/ - if(error) { - if(img_data != NULL) { - lv_free(img_data); - } - LV_LOG_WARN("error %" LV_PRIu32 ": %s\n", error, lodepng_error_text(error)); - return LV_RES_INV; - } - - /*Convert the image to the system's color depth*/ - convert_color_depth(img_data, png_width * png_height); - dsc->img_data = img_data; - return LV_RES_OK; /*The image is fully decoded. Return with its pointer*/ } } - /*If it's a PNG file in a C array...*/ else if(dsc->src_type == LV_IMAGE_SRC_VARIABLE) { - const lv_image_dsc_t * img_dsc = dsc->src; - unsigned png_width; /*Not used, just required by the decoder*/ - unsigned png_height; /*Not used, just required by the decoder*/ - - /*Decode the image in ARGB8888 */ - error = lodepng_decode32(&img_data, &png_width, &png_height, img_dsc->data, img_dsc->data_size); - - if(error) { - if(img_data != NULL) { - lv_free(img_data); - } - return LV_RES_INV; - } - - /*Convert the image to the system's color depth*/ - convert_color_depth(img_data, png_width * png_height); - - dsc->img_data = img_data; - return LV_RES_OK; /*Return with its pointer*/ + const lv_img_dsc_t * img_dsc = dsc->src; + png_data = img_dsc->data; + png_data_size = img_dsc->data_size; + } + else { + return LV_RES_INV; } - return LV_RES_INV; /*If not returned earlier then it failed*/ + lv_cache_lock(); + lv_cache_entry_t * cache = lv_cache_add(dsc->header.w * dsc->header.h * 4); + if(cache == NULL) { + lv_cache_unlock(); + return LV_RES_INV; + } + + uint32_t t = lv_tick_get(); + const void * decoded_img = decode_png_data(png_data, png_data_size); + t = lv_tick_elaps(t); + cache->weight = t; + cache->data = decoded_img; + cache->free_data = 1; + if(dsc->src_type == LV_IMAGE_SRC_FILE) { + cache->src = lv_strdup(dsc->src); + cache->src_type = LV_CACHE_SRC_TYPE_STR; + cache->free_src = 1; + lv_free((void *)png_data); + } + else { + cache->src_type = LV_CACHE_SRC_TYPE_PTR; + cache->src = dsc->src; + } + + dsc->img_data = lv_cache_get_data(cache); + dsc->user_data = cache; + + lv_cache_unlock(); + return LV_RES_OK; /*If not returned earlier then it failed*/ } -/** - * Free the allocated resources - */ -static void decoder_close(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc) +static void decoder_close(lv_image_decoder_t * dec, lv_image_decoder_dsc_t * dsc) { - LV_UNUSED(decoder); /*Unused*/ - if(dsc->img_data) { - lv_free((uint8_t *)dsc->img_data); - dsc->img_data = NULL; - } + LV_UNUSED(dec); + + lv_cache_lock(); + lv_cache_release(dsc->user_data); + lv_cache_unlock(); } + +static lv_res_t try_cache(lv_image_decoder_dsc_t * dsc) +{ + lv_cache_lock(); + if(dsc->src_type == LV_IMAGE_SRC_FILE) { + const char * fn = dsc->src; + + lv_cache_entry_t * cache = lv_cache_find(fn, LV_CACHE_SRC_TYPE_STR, 0, 0); + if(cache) { + dsc->img_data = lv_cache_get_data(cache); + dsc->user_data = cache; /*Save the cache to release it in decoder_close*/ + lv_cache_unlock(); + return LV_RES_OK; + } + } + + else if(dsc->src_type == LV_IMAGE_SRC_VARIABLE) { + const lv_img_dsc_t * img_dsc = dsc->src; + + lv_cache_entry_t * cache = lv_cache_find(img_dsc, LV_CACHE_SRC_TYPE_PTR, 0, 0); + if(cache) { + dsc->img_data = lv_cache_get_data(cache); + dsc->user_data = cache; /*Save the cache to release it in decoder_close*/ + lv_cache_unlock(); + return LV_RES_OK; + } + } + + lv_cache_unlock(); + return LV_RES_INV; +} + +static const void * decode_png_data(const void * png_data, size_t png_data_size) +{ + unsigned png_width; /*Not used, just required by the decoder*/ + unsigned png_height; /*Not used, just required by the decoder*/ + uint8_t * img_data = NULL; + + /*Decode the image in ARGB8888 */ + unsigned error = lodepng_decode32(&img_data, &png_width, &png_height, png_data, png_data_size); + + if(error) { + if(img_data != NULL) lv_free(img_data); + return NULL; + } + + /*Convert the image to the system's color depth*/ + convert_color_depth(img_data, png_width * png_height); + + return img_data; + +} + + /** * If the display is not in 32 bit format (ARGB888) then convert the image to the current color depth * @param img the ARGB888 image diff --git a/src/libs/qrcode/lv_qrcode.c b/src/libs/qrcode/lv_qrcode.c index 37cca52cc..33b672df3 100644 --- a/src/libs/qrcode/lv_qrcode.c +++ b/src/libs/qrcode/lv_qrcode.c @@ -224,7 +224,9 @@ static void lv_qrcode_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj) LV_UNUSED(class_p); lv_image_dsc_t * img_dsc = lv_canvas_get_image(obj); - lv_image_cache_invalidate_src(img_dsc); + lv_cache_lock(); + lv_cache_invalidate(lv_cache_find(img_dsc, LV_CACHE_SRC_TYPE_PTR, 0, 0)); + lv_cache_unlock(); if(!img_dsc->data) { return; diff --git a/src/lv_conf_internal.h b/src/lv_conf_internal.h index e84993e70..d5e93b789 100644 --- a/src/lv_conf_internal.h +++ b/src/lv_conf_internal.h @@ -689,20 +689,18 @@ #endif #endif -/*Default image cache size. Image caching keeps some images opened. - *If only the built-in image formats are used there is no real advantage of caching. - *With other image decoders (e.g. PNG or JPG) caching save the continuous open/decode of images. - *However the opened images consume additional RAM. - *0: to disable caching*/ -#ifndef LV_IMAGE_CACHE_DEF_SIZE - #ifdef CONFIG_LV_IMAGE_CACHE_DEF_SIZE - #define LV_IMAGE_CACHE_DEF_SIZE CONFIG_LV_IMAGE_CACHE_DEF_SIZE +/*Default cache size in bytes. + *Used by image decoders such as `lv_png` to keep the decoded image in the memory. + *Data larger than the size of the cache also can be allocated but + *will be dropped immediately after usage.*/ +#ifndef LV_CACHE_DEF_SIZE + #ifdef CONFIG_LV_CACHE_DEF_SIZE + #define LV_CACHE_DEF_SIZE CONFIG_LV_CACHE_DEF_SIZE #else - #define LV_IMAGE_CACHE_DEF_SIZE 0 + #define LV_CACHE_DEF_SIZE 0 #endif #endif - /*Number of stops allowed per gradient. Increase this to allow more stops. *This adds (sizeof(lv_color_t) + 1) bytes per additional stop*/ #ifndef LV_GRADIENT_MAX_STOPS diff --git a/src/lv_init.c b/src/lv_init.c index 0305a1cd2..0f00a5438 100644 --- a/src/lv_init.c +++ b/src/lv_init.c @@ -19,7 +19,8 @@ #include "libs/png/lv_png.h" #include "libs/sjpg/lv_sjpg.h" #include "draw/lv_draw.h" -#include "draw/lv_image_cache_builtin.h" +#include "misc/lv_cache.h" +#include "misc/lv_cache_builtin.h" #include "misc/lv_async.h" #include "misc/lv_fs.h" @@ -147,7 +148,11 @@ void lv_init(void) _lv_image_decoder_init(); - _lv_image_cache_builtin_init(); + _lv_cache_init(); + _lv_cache_builtin_init(); + lv_cache_lock(); + lv_cache_set_max_size(LV_CACHE_DEF_SIZE); + lv_cache_unlock(); /*Test if the IDE has UTF-8 encoding*/ const char * txt = "Á"; diff --git a/src/misc/lv_cache.c b/src/misc/lv_cache.c new file mode 100644 index 000000000..875192699 --- /dev/null +++ b/src/misc/lv_cache.c @@ -0,0 +1,115 @@ +/** + * @file lv_cache.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_cache.h" +#include "../stdlib/lv_string.h" +#include "../osal/lv_os.h" +#include "../core/lv_global.h" + +/********************* + * DEFINES + *********************/ +#define _cache_manager LV_GLOBAL_DEFAULT()->cache_manager + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +void _lv_cache_init(void) +{ + lv_memzero(&_cache_manager, sizeof(lv_cache_manager_t)); + lv_mutex_init(&_cache_manager.mutex); +} + +lv_cache_entry_t * lv_cache_add(size_t size) +{ + LV_ASSERT(_cache_manager.locked); + if(_cache_manager.add_cb == NULL) return NULL; + + return _cache_manager.add_cb(size); +} + +lv_cache_entry_t * lv_cache_find(const void * src_ptr, lv_cache_src_type_t src_type, uint32_t param1, uint32_t param2) +{ + LV_ASSERT(_cache_manager.locked); + if(_cache_manager.find_cb == NULL) return NULL; + + return _cache_manager.find_cb(src_ptr, src_type, param1, param2); +} + + +void lv_cache_invalidate(lv_cache_entry_t * entry) +{ + LV_ASSERT(_cache_manager.locked); + if(_cache_manager.invalidate_cb == NULL) return; + + _cache_manager.invalidate_cb(entry); +} + +const void * lv_cache_get_data(lv_cache_entry_t * entry) +{ + LV_ASSERT(_cache_manager.locked); + if(_cache_manager.get_data_cb == NULL) return NULL; + + const void * data = _cache_manager.get_data_cb(entry); + return data; +} + +void lv_cache_release(lv_cache_entry_t * entry) +{ + LV_ASSERT(_cache_manager.locked); + if(_cache_manager.release_cb == NULL) return; + + _cache_manager.release_cb(entry); +} + +void lv_cache_set_max_size(size_t size) +{ + LV_ASSERT(_cache_manager.locked); + if(_cache_manager.set_max_size_cb == NULL) return; + + _cache_manager.set_max_size_cb(size); + _cache_manager.max_size = size; +} + +size_t lv_cache_get_max_size(void) +{ + return _cache_manager.max_size; +} + +void lv_cache_lock(void) +{ + lv_mutex_lock(&_cache_manager.mutex); + _cache_manager.locked = 1; +} + +void lv_cache_unlock(void) +{ + _cache_manager.locked = 0; + lv_mutex_unlock(&_cache_manager.mutex); +} + +/********************** + * STATIC FUNCTIONS + **********************/ diff --git a/src/misc/lv_cache.h b/src/misc/lv_cache.h new file mode 100644 index 000000000..2237c4c96 --- /dev/null +++ b/src/misc/lv_cache.h @@ -0,0 +1,219 @@ +/** + * @file lv_cache.h + * + */ + +#ifndef LV_CACHE_H +#define LV_CACHE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include +#include +#include "../osal/lv_os.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +typedef enum { + LV_CACHE_SRC_TYPE_PTR, + LV_CACHE_SRC_TYPE_STR, + _LV_CACHE_SRC_TYPE_LAST, +} lv_cache_src_type_t; + +typedef struct { + /**The image source or other source related to the cache content.*/ + const void * src; + + lv_cache_src_type_t src_type; + + /** Some extra parameters to describe the source. E.g. the current frame of an animation*/ + uint32_t param1; + uint32_t param2; + + /** The data to cache*/ + const void * data; + + /** Size of data in bytes*/ + uint32_t data_size; + + /** On access to any cache entry, `life` of each cache entry will be incremented by their own `weight` to keep the entry alive longer*/ + uint32_t weight; + + /** The current `life`. Entries with the smallest life will be purged from the cache if a new entry needs to be cached*/ + int32_t life; + + /** Count how many times the cached data is being used. + * It will be incremented in lv_cache_get_data and decremented in lv_cache_release. + * A data will dropped from the cache only if its usage_count is zero */ + uint32_t usage_count; + + /** Call `lv_free` on `src` when the entry is removed from the cache */ + uint32_t free_src : 1; + + /** Call `lv_draw_buf_free` on `data` when the entry is removed from the cache */ + uint32_t free_data : 1; + + /** The cache entry was larger then the max cache size so only a temporary entry was allocated + * The entry will be closed and freed in `lv_cache_release` automatically*/ + uint32_t temporary : 1; + + /**Any user data if needed*/ + void * user_data; +} lv_cache_entry_t; + + +/** + * Add a new entry to the cache with the given size. + * It won't allocate any buffers just free enough space to be a new entry + * with `size` bytes fits. + * @param size the size of the new entry in bytes + * @return a handler for the new cache entry + */ +typedef lv_cache_entry_t * (*lv_cache_add_cb)(size_t size); + +/** + * Find a cache entry + * @param src_ptr pointer to the source data + * @param src_type source type (`LV_CACHE_SRC_TYPE_PTR` or `LV_CACHE_SRC_TYPE_STR`) + * @param param1 param1, which was set when the cache was added + * @param param2 param2, which was set when the cache was added + * @return the cache entry with given source and parameters or NULL if not found + */ +typedef lv_cache_entry_t * (*lv_cache_find_cb)(const void * src_ptr, lv_cache_src_type_t src_type, uint32_t param1, + uint32_t param2); + +/** + * Invalidate (drop) a cache entry + * @param entry the entry to invalidate. (can be retrieved by `lv_cache_find()`) + */ +typedef void (*lv_cache_invalidate_cb)(lv_cache_entry_t * entry); + +/** + * Get the data of a cache entry. + * It is considered a cached data access so the cache manager can count that + * this entry was used on more times, and therefore it's more relevant. + * It also increments entry->usage_count to indicate that the data is being used + * and cannot be dropped. + * @param entry the cache entry whose data should be retrieved + */ +typedef const void * (*lv_cache_get_data_cb)(lv_cache_entry_t * entry); + +/** + * Mark the cache entry as unused. It decrements entry->usage_count. + * @param entry the cache entry to invalidate + */ +typedef void (*lv_cache_release_cb)(lv_cache_entry_t * entry); + +/** + * Set maximum cache size in bytes. + * @param size the max size in byes + */ +typedef void (*lv_cache_set_max_size_cb)(size_t size); + +typedef struct { + lv_cache_add_cb add_cb; + lv_cache_find_cb find_cb; + lv_cache_invalidate_cb invalidate_cb; + lv_cache_get_data_cb get_data_cb; + lv_cache_release_cb release_cb; + lv_cache_set_max_size_cb set_max_size_cb; + + lv_mutex_t mutex; + size_t max_size; + uint32_t locked : 1; /**< Show the mutex state, used to log unlocked cache access*/ +} lv_cache_manager_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize the cache module + */ +void _lv_cache_init(void); + +/** + * Add a new entry to the cache with the given size. + * It won't allocate any buffers just free enough space to be a new entry + * with `size` bytes fits. + * @param size the size of the new entry in bytes + * @return a handler for the new cache entry + */ +lv_cache_entry_t * lv_cache_add(size_t size); + +/** + * Find a cache entry with pointer source type + * @param src_ptr pointer to the source data + * @param src_type source type (`LV_CACHE_SRC_TYPE_PTR` or `LV_CACHE_SRC_TYPE_STR`) + * @param param1 param1, which was set when the cache was added + * @param param2 param2, which was set when the cache was added + * @return the cache entry with given source and parameters or NULL if not found + */ +lv_cache_entry_t * lv_cache_find(const void * src, lv_cache_src_type_t src_type, uint32_t param1, uint32_t param2); + +/** + * Invalidate (drop) a cache entry + * @param entry the entry to invalidate. (can be retrieved by `lv_cache_find()`) + */ +void lv_cache_invalidate(lv_cache_entry_t * entry); + +/** + * Get the data of a cache entry. + * It is considered a cached data access so the cache manager can count that + * this entry was used on more times, and therefore it's more relevant. + * It also increments entry->usage_count to indicate that the data is being used + * and cannot be dropped. + * @param entry the cache entry whose data should be retrieved + */ +const void * lv_cache_get_data(lv_cache_entry_t * entry); + +/** + * Mark the cache entry as unused. It decrements entry->usage_count. + * @param entry + */ +void lv_cache_release(lv_cache_entry_t * entry); + +/** + * Set maximum cache size in bytes. + * @param size the max size in byes + */ +void lv_cache_set_max_size(size_t size); + +/** + * Get the max size of the cache + * @return the max size in bytes + */ +size_t lv_cache_get_max_size(void); + +/** + * Lock the mutex of the cache. + * Needs to be called manually before any cache operation, + */ +void lv_cache_lock(void); + +/** + * Unlock the mutex of the cache. + * Needs to be called manually after any cache operation, + */ +void lv_cache_unlock(void); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_CACHE_H*/ diff --git a/src/misc/lv_cache_builtin.c b/src/misc/lv_cache_builtin.c new file mode 100644 index 000000000..bd69e8a41 --- /dev/null +++ b/src/misc/lv_cache_builtin.c @@ -0,0 +1,194 @@ +/** + * @file lv_image_cache.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_cache.h" +#include "../stdlib/lv_string.h" +#include "../core/lv_global.h" +#include "../misc/lv_ll.h" +#include "../osal/lv_os.h" + +/********************* + * DEFINES + *********************/ +#define _cache_manager LV_GLOBAL_DEFAULT()->cache_manager +#define dsc LV_GLOBAL_DEFAULT()->cache_builtin_dsc + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +static lv_cache_entry_t * add_cb(size_t size); +static lv_cache_entry_t * find_cb(const void * src, lv_cache_src_type_t src_type, uint32_t param1, uint32_t param2); +static void invalidate_cb(lv_cache_entry_t * entry); +static const void * get_data_cb(lv_cache_entry_t * entry); +static void release_cb(lv_cache_entry_t * entry); +static void set_max_size_cb(size_t new_size); +static bool drop_yougest(void); + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +void _lv_cache_builtin_init(void) +{ + lv_memzero(&_cache_manager, sizeof(lv_cache_manager_t)); + _cache_manager.add_cb = add_cb; + _cache_manager.find_cb = find_cb; + _cache_manager.invalidate_cb = invalidate_cb; + _cache_manager.get_data_cb = get_data_cb; + _cache_manager.release_cb = release_cb; + _cache_manager.set_max_size_cb = set_max_size_cb; + + _lv_ll_init(&dsc.entry_ll, sizeof(lv_cache_entry_t)); +} + + +/********************** + * STATIC FUNCTIONS + **********************/ + +static lv_cache_entry_t * add_cb(size_t size) +{ + size_t max_size = lv_cache_get_max_size(); + /*Can't cache data larger than max size*/ + + bool temporary = size > max_size ? true : false; + if(!temporary) { + /*Keep dropping items until there is enough space*/ + while(dsc.cur_size + size > _cache_manager.max_size) { + bool ret = drop_yougest(); + + /*No item could be dropped. + *It can happen because the usage_count of the remaining items are not zero.*/ + if(ret == false) { + temporary = true; + break; + } + } + + } + + lv_cache_entry_t * e = _lv_ll_ins_head(&dsc.entry_ll); + lv_memzero(e, sizeof(lv_cache_entry_t)); + e->data_size = size; + e->weight = 1; + e->temporary = temporary; + + if(temporary) { + LV_LOG_USER("cache add temporary: %"LV_PRIu32, (uint32_t)size); + } + else { + LV_LOG_USER("cache add: %"LV_PRIu32, (uint32_t)size); + dsc.cur_size += size; + } + + return e; +} + +static lv_cache_entry_t * find_cb(const void * src, lv_cache_src_type_t src_type, uint32_t param1, uint32_t param2) +{ + lv_cache_entry_t * e = _lv_ll_get_head(&dsc.entry_ll); + while(e) { + if(param1 == e->param1 && param2 == e->param2 && src_type == e->src_type && + ((src_type == LV_CACHE_SRC_TYPE_PTR && src == e->src) || + (src_type == LV_CACHE_SRC_TYPE_STR && strcmp(src, e->src) == 0))) { + return e; + } + + e = _lv_ll_get_next(&dsc.entry_ll, e); + } + + return NULL; +} + +static void invalidate_cb(lv_cache_entry_t * entry) +{ + if(entry == NULL) return; + + dsc.cur_size -= entry->data_size; + LV_LOG_USER("cache drop %"LV_PRIu32, (uint32_t)entry->data_size); + + if(entry->free_src) lv_free((void *)entry->src); + if(entry->free_data) lv_draw_buf_free((void *)entry->data); + + _lv_ll_remove(&dsc.entry_ll, entry); + lv_free(entry); +} + +static const void * get_data_cb(lv_cache_entry_t * entry) +{ + lv_cache_entry_t * e = _lv_ll_get_head(&dsc.entry_ll); + while(e) { + e->life += e->weight; + e = _lv_ll_get_next(&dsc.entry_ll, e); + } + + entry->usage_count++; + + return entry->data; +} + +static void release_cb(lv_cache_entry_t * entry) +{ + if(entry == NULL) return; + + if(entry->temporary) { + invalidate_cb(entry); + } + else { + if(entry->usage_count == 0) { + LV_LOG_ERROR("More lv_cache_release than lv_cache_get_data"); + return; + } + entry->usage_count--; + } +} + +static void set_max_size_cb(size_t new_size) +{ + while(dsc.cur_size > new_size) { + bool ret = drop_yougest(); + + /*No item could be dropped. + *It can happen because the usage_count of the remaining items are not zero.*/ + if(ret == false) return; + } +} + +static bool drop_yougest(void) +{ + + int32_t life_min = INT32_MAX; + lv_cache_entry_t * e_min = NULL; + + lv_cache_entry_t * e = _lv_ll_get_head(&dsc.entry_ll); + while(e) { + if(e->life < life_min && e->usage_count == 0) e_min = e; + e = _lv_ll_get_next(&dsc.entry_ll, e); + } + + if(e_min == NULL) { + return false; + } + + invalidate_cb(e_min); + return true; + +} diff --git a/src/misc/lv_cache_builtin.h b/src/misc/lv_cache_builtin.h new file mode 100644 index 000000000..7b88cfc6d --- /dev/null +++ b/src/misc/lv_cache_builtin.h @@ -0,0 +1,45 @@ +/** + * @file lv_cache_builtin.h + * + */ + +#ifndef LV_CACHE_BUILTIN_H +#define LV_CACHE_BUILTIN_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "lv_ll.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +typedef struct { + uint32_t cur_size; + lv_ll_t entry_ll; +} lv_cache_builtin_dsc_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +void _lv_cache_builtin_init(void); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_CACHE_BUILTIN_H*/ diff --git a/src/osal/lv_os.h b/src/osal/lv_os.h index 4ebff0144..15d65dbf8 100644 --- a/src/osal/lv_os.h +++ b/src/osal/lv_os.h @@ -19,11 +19,12 @@ extern "C" { *********************/ #include "../lv_conf_internal.h" -#if LV_USE_OS - #include "../misc/lv_types.h" +#include -#if LV_USE_OS == LV_OS_PTHREAD +#if LV_USE_OS == LV_OS_NONE +#include "lv_os_none.h" +#elif LV_USE_OS == LV_OS_PTHREAD #include "lv_pthread.h" #elif LV_USE_OS == LV_OS_FREERTOS #include "lv_freertos.h" @@ -143,8 +144,6 @@ lv_res_t lv_thread_sync_delete(lv_thread_sync_t * sync); * MACROS **********************/ -#endif /*LV_USE_OS*/ - #ifdef __cplusplus } /*extern "C"*/ #endif diff --git a/src/osal/lv_os_none.c b/src/osal/lv_os_none.c new file mode 100644 index 000000000..75c9f1fea --- /dev/null +++ b/src/osal/lv_os_none.c @@ -0,0 +1,122 @@ +/** + * @file lv_os_none.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_os.h" + +#if LV_USE_OS == LV_OS_NONE +#include "../misc/lv_types.h" +#include "../misc/lv_assert.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + + +lv_res_t lv_thread_init(lv_thread_t * thread, lv_thread_prio_t prio, void (*callback)(void *), size_t stack_size, + void * user_data) +{ + LV_UNUSED(thread); + LV_UNUSED(callback); + LV_UNUSED(prio); + LV_UNUSED(stack_size); + LV_UNUSED(user_data); + LV_ASSERT(0); + return LV_RES_INV; +} + +lv_res_t lv_thread_delete(lv_thread_t * thread) +{ + LV_UNUSED(thread); + LV_ASSERT(0); + return LV_RES_INV; +} + + +lv_res_t lv_mutex_init(lv_mutex_t * mutex) +{ + LV_UNUSED(mutex); + return LV_RES_OK; +} + +lv_res_t lv_mutex_lock(lv_mutex_t * mutex) +{ + LV_UNUSED(mutex); + return LV_RES_OK; +} + +lv_res_t lv_mutex_lock_isr(lv_mutex_t * mutex) +{ + LV_UNUSED(mutex); + return LV_RES_OK; +} + +lv_res_t lv_mutex_unlock(lv_mutex_t * mutex) +{ + LV_UNUSED(mutex); + return LV_RES_OK; +} + +lv_res_t lv_mutex_delete(lv_mutex_t * mutex) +{ + LV_UNUSED(mutex); + return LV_RES_OK; +} + +lv_res_t lv_thread_sync_init(lv_thread_sync_t * sync) +{ + LV_UNUSED(sync); + LV_ASSERT(0); + return LV_RES_INV; +} + +lv_res_t lv_thread_sync_wait(lv_thread_sync_t * sync) +{ + LV_UNUSED(sync); + LV_ASSERT(0); + return LV_RES_INV; +} + +lv_res_t lv_thread_sync_signal(lv_thread_sync_t * sync) +{ + LV_UNUSED(sync); + LV_ASSERT(0); + return LV_RES_INV; +} + +lv_res_t lv_thread_sync_delete(lv_thread_sync_t * sync) +{ + LV_UNUSED(sync); + LV_ASSERT(0); + return LV_RES_INV; +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +#endif /*LV_USE_OS == LV_OS_NONE*/ diff --git a/src/draw/lv_image_cache_builtin.h b/src/osal/lv_os_none.h similarity index 65% rename from src/draw/lv_image_cache_builtin.h rename to src/osal/lv_os_none.h index ca55beffe..e08a0dc42 100644 --- a/src/draw/lv_image_cache_builtin.h +++ b/src/osal/lv_os_none.h @@ -1,10 +1,10 @@ /** - * @file lv_image_cache_builtin.h + * @file lv_os_none.h * */ -#ifndef LV_IMAGE_CACHE_BUILTIN_H -#define LV_IMAGE_CACHE_BUILTIN_H +#ifndef LV_OS_NONE_H +#define LV_OS_NONE_H #ifdef __cplusplus extern "C" { @@ -13,6 +13,7 @@ extern "C" { /********************* * INCLUDES *********************/ +#if LV_USE_OS == LV_OS_NONE /********************* * DEFINES @@ -21,19 +22,22 @@ extern "C" { /********************** * TYPEDEFS **********************/ +typedef int lv_mutex_t; +typedef int lv_thread_t; +typedef int lv_thread_sync_t; /********************** * GLOBAL PROTOTYPES **********************/ -void _lv_image_cache_builtin_init(void); - /********************** * MACROS **********************/ +#endif /*LV_USE_OS == LV_OS_NONE*/ + #ifdef __cplusplus } /*extern "C"*/ #endif -#endif /*LV_IMAGE_CACHE_BUILTIN_H*/ +#endif /*LV_OS_NONE_H*/ diff --git a/src/stdlib/clib/lv_string_clib.c b/src/stdlib/clib/lv_string_clib.c index ea6f09ac3..93aacbe60 100644 --- a/src/stdlib/clib/lv_string_clib.c +++ b/src/stdlib/clib/lv_string_clib.c @@ -10,6 +10,10 @@ #include "../lv_string.h" #include +#if LV_USE_STDLIB_MALLOC == LV_STDLIB_BUILTIN + #include "../lv_mem.h" +#endif + /********************* * DEFINES *********************/ @@ -66,7 +70,17 @@ char * lv_strcpy(char * dst, const char * src) char * lv_strdup(const char * src) { + /*strdup uses malloc, so use the built in malloc if it's enabled */ +#if LV_USE_STDLIB_MALLOC == LV_STDLIB_BUILTIN + size_t len = lv_strlen(src) + 1; + char * dst = lv_malloc(len); + if(dst == NULL) return NULL; + + lv_memcpy(dst, src, len); /*do memcpy is faster than strncpy when length is known*/ + return dst; +#else return strdup(src); +#endif } /********************** diff --git a/src/widgets/canvas/lv_canvas.c b/src/widgets/canvas/lv_canvas.c index 666bd5a20..77122c35c 100644 --- a/src/widgets/canvas/lv_canvas.c +++ b/src/widgets/canvas/lv_canvas.c @@ -76,7 +76,9 @@ void lv_canvas_set_buffer(lv_obj_t * obj, void * buf, lv_coord_t w, lv_coord_t h canvas->dsc.data_size = w * h * lv_color_format_get_size(cf); lv_image_set_src(obj, &canvas->dsc); - lv_image_cache_invalidate_src(&canvas->dsc); + lv_cache_lock(); + lv_cache_invalidate(lv_cache_find(&canvas->dsc, LV_CACHE_SRC_TYPE_PTR, 0, 0)); + lv_cache_unlock(); } void lv_canvas_set_px(lv_obj_t * obj, lv_coord_t x, lv_coord_t y, lv_color_t color, lv_opa_t opa) @@ -336,7 +338,10 @@ static void lv_canvas_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj) LV_TRACE_OBJ_CREATE("begin"); lv_canvas_t * canvas = (lv_canvas_t *)obj; - lv_image_cache_invalidate_src(&canvas->dsc); + + lv_cache_lock(); + lv_cache_invalidate(lv_cache_find(&canvas->dsc, LV_CACHE_SRC_TYPE_PTR, 0, 0)); + lv_cache_unlock(); }