diff --git a/lv_conf_template.h b/lv_conf_template.h index 28582db1c7..d17e61a921 100644 --- a/lv_conf_template.h +++ b/lv_conf_template.h @@ -271,8 +271,8 @@ /*Default cache size in bytes. *Used by image decoders such as `lv_lodepng` 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.*/ + *If size is not set to 0, the decoder will fail to decode when the cache is full. + *If size is 0, the cache function is not enabled and the decoded mem will be released immediately after use.*/ #define LV_CACHE_DEF_SIZE 0 /*Number of stops allowed per gradient. Increase this to allow more stops. diff --git a/lvgl.h b/lvgl.h index a819e499ab..ff51893d5a 100644 --- a/lvgl.h +++ b/lvgl.h @@ -35,8 +35,6 @@ extern "C" { #include "src/misc/lv_anim_timeline.h" #include "src/misc/lv_profiler_builtin.h" #include "src/misc/lv_rb.h" -#include "src/misc/lv_lru_rb.h" - #include "src/tick/lv_tick.h" diff --git a/src/core/lv_global.h b/src/core/lv_global.h index 06e8c7c806..5d44c33723 100644 --- a/src/core/lv_global.h +++ b/src/core/lv_global.h @@ -17,8 +17,6 @@ extern "C" { #include -#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" @@ -104,9 +102,11 @@ typedef struct _lv_global_t { lv_draw_buf_handlers_t draw_buf_handlers; lv_ll_t img_decoder_ll; - lv_cache_manager_t cache_manager; - lv_cache_builtin_dsc_t cache_builtin_dsc; + +#if LV_CACHE_DEF_SIZE > 0 + lv_cache_t * img_cache; size_t cache_builtin_max_size; +#endif lv_draw_global_info_t draw_info; #if defined(LV_DRAW_SW_SHADOW_CACHE_SIZE) && LV_DRAW_SW_SHADOW_CACHE_SIZE > 0 @@ -160,6 +160,10 @@ typedef struct _lv_global_t { struct _lv_freetype_context_t * ft_context; #endif +#if LV_USE_TINY_TTF + lv_cache_t * tiny_ttf_cache; +#endif + #if LV_USE_FONT_COMPRESSED lv_font_fmt_rle_t font_fmt_rle; #endif diff --git a/src/draw/lv_draw.h b/src/draw/lv_draw.h index b143f2c34a..aaf9484b36 100644 --- a/src/draw/lv_draw.h +++ b/src/draw/lv_draw.h @@ -18,7 +18,6 @@ extern "C" { #include "../misc/lv_style.h" #include "../misc/lv_text.h" #include "../misc/lv_profiler.h" -#include "../misc/lv_cache.h" #include "lv_image_decoder.h" #include "../osal/lv_os.h" #include "lv_draw_buf.h" diff --git a/src/draw/lv_image_decoder.c b/src/draw/lv_image_decoder.c index bdfb32b8d4..ebea3a6570 100644 --- a/src/draw/lv_image_decoder.c +++ b/src/draw/lv_image_decoder.c @@ -17,6 +17,7 @@ * DEFINES *********************/ #define img_decoder_ll_p &(LV_GLOBAL_DEFAULT()->img_decoder_ll) +#define img_cache_p (LV_GLOBAL_DEFAULT()->img_cache) /********************** * TYPEDEFS @@ -28,6 +29,13 @@ static uint32_t img_width_to_stride(lv_image_header_t * header); +#if LV_CACHE_DEF_SIZE > 0 +static lv_cache_compare_res_t image_decoder_cache_compare_cb(const lv_image_cache_data_t * lhs, + const lv_image_cache_data_t * rhs); +static void image_decoder_cache_free_cb(lv_image_cache_data_t * entry, void * user_data); + +static lv_result_t try_cache(lv_image_decoder_dsc_t * dsc); +#endif /********************** * STATIC VARIABLES **********************/ @@ -46,6 +54,15 @@ static uint32_t img_width_to_stride(lv_image_header_t * header); void _lv_image_decoder_init(void) { _lv_ll_init(img_decoder_ll_p, sizeof(lv_image_decoder_t)); + +#if LV_CACHE_DEF_SIZE > 0 + img_cache_p = lv_cache_create(&lv_cache_class_lru_rb_size, + sizeof(lv_image_cache_data_t), LV_CACHE_DEF_SIZE, (lv_cache_ops_t) { + .compare_cb = (lv_cache_compare_cb_t)image_decoder_cache_compare_cb, + .create_cb = NULL, + .free_cb = (lv_cache_free_cb_t)image_decoder_cache_free_cb, + }); +#endif } /** @@ -53,6 +70,9 @@ void _lv_image_decoder_init(void) */ void _lv_image_decoder_deinit(void) { +#if LV_CACHE_DEF_SIZE > 0 + lv_cache_destroy(img_cache_p, NULL); +#endif _lv_ll_clear(img_decoder_ll_p); } @@ -134,6 +154,14 @@ lv_result_t lv_image_decoder_open(lv_image_decoder_dsc_t * dsc, const void * src if(dsc->header.stride == 0) dsc->header.stride = img_width_to_stride(&dsc->header); dsc->decoder = decoder; + +#if LV_CACHE_DEF_SIZE > 0 + dsc->cache = img_cache_p; + + /*Check the cache first*/ + if(try_cache(dsc) == LV_RESULT_OK) return LV_RESULT_OK; +#endif + res = decoder->open_cb(decoder, dsc, args); /*Opened successfully. It is a good decoder for this image source*/ @@ -229,6 +257,36 @@ void lv_image_decoder_set_close_cb(lv_image_decoder_t * decoder, lv_image_decode decoder->close_cb = close_cb; } +void lv_image_decoder_set_cache_free_cb(lv_image_decoder_t * decoder, lv_cache_free_cb_t cache_free_cb) +{ + decoder->cache_free_cb = cache_free_cb; +} + +#if LV_CACHE_DEF_SIZE > 0 +lv_cache_entry_t * lv_image_decoder_add_to_cache(lv_image_decoder_t * decoder, + lv_image_cache_data_t * search_key, + const lv_draw_buf_t * decoded, void * user_data) +{ + lv_cache_entry_t * cache_entry = lv_cache_add(img_cache_p, search_key, NULL); + if(cache_entry == NULL) { + return NULL; + } + + lv_image_cache_data_t * cached_data; + cached_data = lv_cache_entry_get_data(cache_entry); + + /*Set the cache entry to decoder data*/ + cached_data->decoded = decoded; + if(cached_data->src_type == LV_IMAGE_SRC_FILE) { + cached_data->src = lv_strdup(cached_data->src); + } + cached_data->user_data = user_data; /*Need to free data on cache invalidate instead of decoder_close*/ + cached_data->decoder = decoder; + + return cache_entry; +} +#endif + lv_draw_buf_t * lv_image_decoder_post_process(lv_image_decoder_dsc_t * dsc, lv_draw_buf_t * decoded) { if(decoded == NULL) return NULL; /*No need to adjust*/ @@ -280,3 +338,56 @@ static uint32_t img_width_to_stride(lv_image_header_t * header) return ((uint32_t)header->w * lv_color_format_get_bpp(header->cf) + 7) >> 3; } } + +#if LV_CACHE_DEF_SIZE > 0 +static lv_cache_compare_res_t image_decoder_cache_compare_cb( + const lv_image_cache_data_t * lhs, + const lv_image_cache_data_t * rhs) +{ + if(lhs->src_type == rhs->src_type) { + if(lhs->src_type == LV_IMAGE_SRC_FILE) { + int32_t cmp_res = lv_strcmp(lhs->src, rhs->src); + if(cmp_res != 0) { + return cmp_res > 0 ? 1 : -1; + } + } + else if(lhs->src_type == LV_IMAGE_SRC_VARIABLE) { + if(lhs->src != rhs->src) { + return lhs->src > rhs->src ? 1 : -1; + } + } + return 0; + } + return lhs->src_type > rhs->src_type ? 1 : -1; +} + +static void image_decoder_cache_free_cb(lv_image_cache_data_t * entry, void * user_data) +{ + LV_UNUSED(user_data); /*Unused*/ + + const lv_image_decoder_t * decoder = entry->decoder; + if(decoder && decoder->cache_free_cb) { + decoder->cache_free_cb(entry, user_data); + } +} + +static lv_result_t try_cache(lv_image_decoder_dsc_t * dsc) +{ + lv_cache_t * cache = dsc->cache; + + lv_image_cache_data_t search_key; + search_key.src_type = dsc->src_type; + search_key.src = dsc->src; + + lv_cache_entry_t * entry = lv_cache_acquire(cache, &search_key, NULL); + + if(entry) { + lv_image_cache_data_t * cached_data = lv_cache_entry_get_data(entry); + dsc->decoded = cached_data->decoded; + dsc->cache_entry = entry; /*Save the cache to release it in decoder_close*/ + return LV_RESULT_OK; + } + + return LV_RESULT_INVALID; +} +#endif diff --git a/src/draw/lv_image_decoder.h b/src/draw/lv_image_decoder.h index 3b15b73b2e..288cfeddf8 100644 --- a/src/draw/lv_image_decoder.h +++ b/src/draw/lv_image_decoder.h @@ -20,6 +20,7 @@ extern "C" { #include "../misc/lv_fs.h" #include "../misc/lv_types.h" #include "../misc/lv_area.h" +#include "../misc/cache/lv_cache.h" /********************* * DEFINES @@ -111,10 +112,22 @@ typedef struct _lv_image_decoder_t { lv_image_decoder_open_f_t open_cb; lv_image_decoder_get_area_cb_t get_area_cb; lv_image_decoder_close_f_t close_cb; - uint32_t cache_data_type; + + lv_cache_free_cb_t cache_free_cb; void * user_data; } lv_image_decoder_t; +typedef struct _lv_image_decoder_cache_data_t { + lv_cache_slot_size_t slot; + + const void * src; + lv_image_src_t src_type; + + const lv_draw_buf_t * decoded; + const lv_image_decoder_t * decoder; + void * user_data; +} lv_image_cache_data_t; + /**Describe an image decoding session. Stores data about the decoding*/ typedef struct _lv_image_decoder_dsc_t { /**The decoder which was able to open the image source*/ @@ -149,8 +162,10 @@ typedef struct _lv_image_decoder_dsc_t { * Can be set in `open` function or set NULL.*/ const char * error_msg; + lv_cache_t * cache; + /**Point to cache entry information*/ - struct _lv_cache_entry_t * cache_entry; + lv_cache_entry_t * cache_entry; /**Store any custom data here is required*/ void * user_data; @@ -268,6 +283,14 @@ void lv_image_decoder_set_get_area_cb(lv_image_decoder_t * decoder, lv_image_dec */ void lv_image_decoder_set_close_cb(lv_image_decoder_t * decoder, lv_image_decoder_close_f_t close_cb); +void lv_image_decoder_set_cache_free_cb(lv_image_decoder_t * decoder, lv_cache_free_cb_t cache_free_cb); + +#if LV_CACHE_DEF_SIZE > 0 +lv_cache_entry_t * lv_image_decoder_add_to_cache(lv_image_decoder_t * decoder, + lv_image_cache_data_t * search_key, + const lv_draw_buf_t * decoded, void * user_data); +#endif + /** * Check the decoded image, make any modification if decoder `args` requires. * @note A new draw buf will be allocated if provided `decoded` is not modifiable or stride mismatch etc. diff --git a/src/draw/sdl/lv_draw_sdl.c b/src/draw/sdl/lv_draw_sdl.c index c9ff069e60..ddbc78f239 100644 --- a/src/draw/sdl/lv_draw_sdl.c +++ b/src/draw/sdl/lv_draw_sdl.c @@ -40,6 +40,7 @@ static void execute_drawing(lv_draw_sdl_unit_t * u); static int32_t dispatch(lv_draw_unit_t * draw_unit, lv_layer_t * layer); static int32_t evaluate(lv_draw_unit_t * draw_unit, lv_draw_task_t * task); +static bool draw_to_texture(lv_draw_sdl_unit_t * u, cache_data_t * data); /********************** * GLOBAL PROTOTYPES @@ -58,13 +59,59 @@ static SDL_Texture * layer_get_texture(lv_layer_t * layer); /********************** * GLOBAL FUNCTIONS **********************/ +static bool sdl_texture_cache_create_cb(cache_data_t * cached_data, void * user_data) +{ + return draw_to_texture((lv_draw_sdl_unit_t *)user_data, cached_data); +} + +static void sdl_texture_cache_free_cb(cache_data_t * cached_data, void * user_data) +{ + LV_UNUSED(user_data); + + lv_free(cached_data->draw_dsc); + SDL_DestroyTexture(cached_data->texture); + cached_data->draw_dsc = NULL; + cached_data->texture = NULL; +} + +static lv_cache_compare_res_t sdl_texture_cache_compare_cb(const cache_data_t * lhs, const cache_data_t * rhs) +{ + if(lhs == rhs) return 0; + + if(lhs->w != rhs->w) { + return lhs->w > rhs->w ? 1 : -1; + } + if(lhs->h != rhs->h) { + return lhs->h > rhs->h ? 1 : -1; + } + + uint32_t lhs_dsc_size = lhs->draw_dsc->dsc_size; + uint32_t rhs_dsc_size = rhs->draw_dsc->dsc_size; + + if(lhs_dsc_size != rhs_dsc_size) { + return lhs_dsc_size > rhs_dsc_size ? 1 : -1; + } + + int cmp_res = memcmp(lhs->draw_dsc, rhs->draw_dsc, lhs->draw_dsc->dsc_size); + + if(cmp_res != 0) { + return cmp_res > 0 ? 1 : -1; + } + + return 0; +} void lv_draw_sdl_init(void) { lv_draw_sdl_unit_t * draw_sdl_unit = lv_draw_create_unit(sizeof(lv_draw_sdl_unit_t)); draw_sdl_unit->base_unit.dispatch_cb = dispatch; draw_sdl_unit->base_unit.evaluate_cb = evaluate; - draw_sdl_unit->texture_cache_data_type = lv_cache_register_data_type(); + draw_sdl_unit->texture_cache = lv_cache_create(&lv_cache_class_lru_rb_count, + sizeof(cache_data_t), 128, (lv_cache_ops_t) { + .compare_cb = (lv_cache_compare_cb_t)sdl_texture_cache_compare_cb, + .create_cb = (lv_cache_create_cb_t)sdl_texture_cache_create_cb, + .free_cb = (lv_cache_free_cb_t)sdl_texture_cache_free_cb, + }); } /********************** @@ -121,34 +168,7 @@ static int32_t evaluate(lv_draw_unit_t * draw_unit, lv_draw_task_t * task) return 0; } -bool compare_cb(const void * data1, const void * data2, size_t data_size) -{ - LV_UNUSED(data_size); - const cache_data_t * d1 = data1; - const cache_data_t * d2 = data2; - - if(d1->w != d2->w) return false; - if(d1->h != d2->h) return false; - - if(d1->draw_dsc->dsc_size != d2->draw_dsc->dsc_size) return false; - - if(memcmp(d1->draw_dsc, d2->draw_dsc, d1->draw_dsc->dsc_size)) return false; - - return true; - -} - -void invalidate_cb(lv_cache_entry_t * e) -{ - const cache_data_t * d = e->data; - lv_free((void *)d->draw_dsc); - SDL_DestroyTexture(d->texture); - lv_free((void *)d); - e->data = NULL; - e->data_size = 0; -} - -static lv_cache_entry_t * draw_to_texture(lv_draw_sdl_unit_t * u) +static bool draw_to_texture(lv_draw_sdl_unit_t * u, cache_data_t * data) { lv_draw_task_t * task = u->task_act; @@ -165,7 +185,6 @@ static lv_cache_entry_t * draw_to_texture(lv_draw_sdl_unit_t * u) lv_display_t * disp = _lv_refr_get_disp_refreshing(); - uint32_t tick = lv_tick_get(); SDL_Texture * texture = NULL; switch(task->type) { case LV_DRAW_TASK_TYPE_FILL: { @@ -210,7 +229,7 @@ static lv_cache_entry_t * draw_to_texture(lv_draw_sdl_unit_t * u) SDL_Surface * surface = IMG_Load(&path[2]); if(surface == NULL) { fprintf(stderr, "could not load image: %s\n", IMG_GetError()); - return NULL; + return false; } SDL_Renderer * renderer = lv_sdl_window_get_renderer(disp); @@ -218,7 +237,7 @@ static lv_cache_entry_t * draw_to_texture(lv_draw_sdl_unit_t * u) break; } default: - return NULL; + return false; } while(dest_layer.draw_task_head) { @@ -244,7 +263,6 @@ static lv_cache_entry_t * draw_to_texture(lv_draw_sdl_unit_t * u) SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND); } - cache_data_t * data = lv_malloc(sizeof(cache_data_t)); lv_draw_dsc_base_t * base_dsc = task->draw_dsc; data->draw_dsc = lv_malloc(base_dsc->dsc_size); @@ -253,14 +271,7 @@ static lv_cache_entry_t * draw_to_texture(lv_draw_sdl_unit_t * u) data->h = lv_area_get_height(&task->area); data->texture = texture; - lv_cache_entry_t * e = lv_cache_add(data, sizeof(cache_data_t), u->texture_cache_data_type, - lv_area_get_size(&task->area) * 4); - e->compare_cb = compare_cb; - e->invalidate_cb = invalidate_cb; - e->weight = lv_tick_elaps(tick); - e->weight += lv_area_get_size(&task->area) / 10000; - if(e->weight == 0) e->weight++; - return e; + return true; } static void blend_texture_layer(lv_draw_sdl_unit_t * u) @@ -310,20 +321,14 @@ static void draw_from_cached_texture(lv_draw_sdl_unit_t * u) void * user_data_saved = data_to_find.draw_dsc->user_data; data_to_find.draw_dsc->user_data = NULL; - lv_cache_lock(); - lv_cache_entry_t * e = lv_cache_find_by_data(&data_to_find, sizeof(data_to_find), u->texture_cache_data_type); - data_to_find.draw_dsc->user_data = user_data_saved; - if(e == NULL) { - printf("cache_miss %d\n", t->type); - e = draw_to_texture(u); - } - - if(e == NULL) { - lv_cache_unlock(); + lv_cache_entry_t * entry_cached = lv_cache_acquire_or_create(u->texture_cache, &data_to_find, u); + if(!entry_cached) { return; } - const cache_data_t * data_cached = lv_cache_get_data(e); + data_to_find.draw_dsc->user_data = user_data_saved; + + cache_data_t * data_cached = lv_cache_entry_get_data(entry_cached); SDL_Texture * texture = data_cached->texture; lv_display_t * disp = _lv_refr_get_disp_refreshing(); SDL_Renderer * renderer = lv_sdl_window_get_renderer(disp); @@ -368,8 +373,7 @@ static void draw_from_cached_texture(lv_draw_sdl_unit_t * u) SDL_RenderSetClipRect(renderer, NULL); - lv_cache_release(e); - lv_cache_unlock(); + lv_cache_release(u->texture_cache, entry_cached, u); } static void execute_drawing(lv_draw_sdl_unit_t * u) diff --git a/src/draw/sdl/lv_draw_sdl.h b/src/draw/sdl/lv_draw_sdl.h index 2fee619877..8f6ed3dfe8 100644 --- a/src/draw/sdl/lv_draw_sdl.h +++ b/src/draw/sdl/lv_draw_sdl.h @@ -14,8 +14,10 @@ extern "C" { * INCLUDES *********************/ #include "../lv_draw.h" + #if LV_USE_DRAW_SDL +#include #include "../../misc/lv_area.h" #include "../../misc/lv_color.h" #include "../../display/lv_display.h" @@ -33,6 +35,7 @@ typedef struct { lv_draw_unit_t base_unit; struct _lv_draw_task_t * task_act; uint32_t texture_cache_data_type; + lv_cache_t * texture_cache; } lv_draw_sdl_unit_t; #if LV_DRAW_SW_SHADOW_CACHE_SIZE diff --git a/src/draw/sw/lv_draw_sw_img.c b/src/draw/sw/lv_draw_sw_img.c index 340ad497f8..6283cb4774 100644 --- a/src/draw/sw/lv_draw_sw_img.c +++ b/src/draw/sw/lv_draw_sw_img.c @@ -14,7 +14,6 @@ #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" @@ -70,6 +69,7 @@ void lv_draw_sw_layer(lv_draw_unit_t * draw_unit, const lv_draw_image_dsc_t * dr new_draw_dsc.src = &img_dsc; lv_draw_sw_image(draw_unit, &new_draw_dsc, coords); + lv_image_cache_drop(&img_dsc); #if LV_USE_LAYER_DEBUG || LV_USE_PARALLEL_DRAW_DEBUG lv_area_t area_rot; diff --git a/src/draw/vg_lite/lv_draw_vg_lite_layer.c b/src/draw/vg_lite/lv_draw_vg_lite_layer.c index 95cec26ff6..7b40d7ce5a 100644 --- a/src/draw/vg_lite/lv_draw_vg_lite_layer.c +++ b/src/draw/vg_lite/lv_draw_vg_lite_layer.c @@ -62,9 +62,7 @@ void lv_draw_vg_lite_layer(lv_draw_unit_t * draw_unit, const lv_draw_image_dsc_t new_draw_dsc.src = &img_dsc; lv_draw_vg_lite_img(draw_unit, &new_draw_dsc, coords); - lv_cache_lock(); - lv_cache_invalidate_by_src(&img_dsc, LV_CACHE_SRC_TYPE_POINTER); - lv_cache_unlock(); + lv_image_cache_invalidate(&img_dsc); } /********************** diff --git a/src/libs/barcode/lv_barcode.c b/src/libs/barcode/lv_barcode.c index 78dd514980..4c3436b3b5 100644 --- a/src/libs/barcode/lv_barcode.c +++ b/src/libs/barcode/lv_barcode.c @@ -197,7 +197,9 @@ static void lv_barcode_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj lv_draw_buf_t * draw_buf = lv_canvas_get_draw_buf(obj); if(draw_buf == NULL) return; + lv_image_cache_drop(draw_buf); + /*@fixme destroy buffer in cache free_cb.*/ lv_draw_buf_destroy(draw_buf); } diff --git a/src/libs/bin_decoder/lv_bin_decoder.c b/src/libs/bin_decoder/lv_bin_decoder.c index 3fd71db63e..91cb8a1532 100644 --- a/src/libs/bin_decoder/lv_bin_decoder.c +++ b/src/libs/bin_decoder/lv_bin_decoder.c @@ -70,8 +70,8 @@ static lv_fs_res_t fs_read_file_at(lv_fs_file_t * f, uint32_t pos, void * buff, static lv_result_t decompress_image(lv_image_decoder_dsc_t * dsc, const lv_image_compressed_t * compressed); -static lv_result_t try_cache(lv_image_decoder_dsc_t * dsc); -static void cache_invalidate_cb(lv_cache_entry_t * entry); +static bool bin_decoder_decode_data(lv_image_decoder_dsc_t * dsc); +static void bin_decoder_cache_free_cb(lv_image_cache_data_t * cached_data, void * user_data); /********************** * STATIC VARIABLES @@ -103,7 +103,7 @@ void lv_bin_decoder_init(void) lv_image_decoder_set_open_cb(decoder, lv_bin_decoder_open); lv_image_decoder_set_get_area_cb(decoder, lv_bin_decoder_get_area); lv_image_decoder_set_close_cb(decoder, lv_bin_decoder_close); - decoder->cache_data_type = lv_cache_register_data_type(); + lv_image_decoder_set_cache_free_cb(decoder, (lv_cache_free_cb_t)bin_decoder_cache_free_cb); } lv_result_t lv_bin_decoder_info(lv_image_decoder_t * decoder, const void * src, lv_image_header_t * header) @@ -173,120 +173,8 @@ lv_result_t lv_bin_decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_d LV_UNUSED(decoder); LV_UNUSED(args); - /*Check the cache first*/ - if(try_cache(dsc) == LV_RESULT_OK) return LV_RESULT_OK; - - lv_fs_res_t res = LV_RESULT_INVALID; - uint32_t t = lv_tick_get(); - - /*Open the file if it's a file*/ - if(dsc->src_type == LV_IMAGE_SRC_FILE) { - /*Support only "*.bin" files*/ - if(lv_strcmp(lv_fs_get_ext(dsc->src), "bin")) return LV_RESULT_INVALID; - - /*If the file was open successfully save the file descriptor*/ - decoder_data_t * decoder_data = get_decoder_data(dsc); - if(decoder_data == NULL) { - return LV_RESULT_INVALID; - } - - dsc->user_data = decoder_data; - lv_fs_file_t * f = lv_malloc(sizeof(*f)); - if(f == NULL) { - free_decoder_data(dsc); - return LV_RESULT_INVALID; - } - - res = lv_fs_open(f, dsc->src, LV_FS_MODE_RD); - if(res != LV_FS_RES_OK) { - LV_LOG_WARN("Open file failed: %d", res); - lv_free(f); - free_decoder_data(dsc); - return LV_RESULT_INVALID; - } - - decoder_data->f = f; /*Now free_decoder_data will take care of the file*/ - - lv_color_format_t cf = dsc->header.cf; - - if(dsc->header.flags & LV_IMAGE_FLAGS_COMPRESSED) { - res = decode_compressed(decoder, dsc); - } - else if(LV_COLOR_FORMAT_IS_INDEXED(cf)) { - /*Palette for indexed image and whole image of A8 image are always loaded to RAM for simplicity*/ - res = decode_indexed(decoder, dsc); - } - else if(LV_COLOR_FORMAT_IS_ALPHA_ONLY(cf)) { - res = decode_alpha_only(decoder, dsc); - } -#if LV_BIN_DECODER_RAM_LOAD - else if(cf == LV_COLOR_FORMAT_ARGB8888 \ - || cf == LV_COLOR_FORMAT_XRGB8888 \ - || cf == LV_COLOR_FORMAT_RGB888 \ - || cf == LV_COLOR_FORMAT_RGB565 \ - || cf == LV_COLOR_FORMAT_RGB565A8) { - res = decode_rgb(decoder, dsc); - } -#else - else { - /* decode them in get_area_cb */ - res = LV_RESULT_OK; - } -#endif - } - - else if(dsc->src_type == LV_IMAGE_SRC_VARIABLE) { - /*The variables should have valid data*/ - lv_image_dsc_t * image = (lv_image_dsc_t *)dsc->src; - if(image->data == NULL) { - return LV_RESULT_INVALID; - } - - lv_color_format_t cf = image->header.cf; - if(dsc->header.flags & LV_IMAGE_FLAGS_COMPRESSED) { - res = decode_compressed(decoder, dsc); - } - else if(LV_COLOR_FORMAT_IS_INDEXED(cf)) { - /*Need decoder data to store converted image*/ - decoder_data_t * decoder_data = get_decoder_data(dsc); - if(decoder_data == NULL) { - return LV_RESULT_INVALID; - } - - res = decode_indexed(decoder, dsc); - } - else if(LV_COLOR_FORMAT_IS_ALPHA_ONLY(cf)) { - /*Alpha only image will need decoder data to store pointer to decoded image, to free it when decoder closes*/ - decoder_data_t * decoder_data = get_decoder_data(dsc); - if(decoder_data == NULL) { - return LV_RESULT_INVALID; - } - - res = decode_alpha_only(decoder, dsc); - } - else { - /*In case of uncompressed formats the image stored in the ROM/RAM. - *So simply give its pointer*/ - - decoder_data_t * decoder_data = get_decoder_data(dsc); - lv_draw_buf_t * decoded = &decoder_data->c_array; - dsc->decoded = decoded; - lv_draw_buf_from_image(decoded, image); - - if(decoded->header.stride == 0) { - /*Use the auto calculated value from decoder_info callback*/ - decoded->header.stride = dsc->header.stride; - } - - res = LV_RESULT_OK; - } - } - - if(res != LV_RESULT_OK) { - free_decoder_data(dsc); - return res; - } - + bool create_res = bin_decoder_decode_data(dsc); + if(create_res == false) return LV_RESULT_INVALID; if(dsc->decoded == NULL) return LV_RESULT_OK; /*Need to read via get_area_cb*/ lv_draw_buf_t * decoded = (lv_draw_buf_t *)dsc->decoded; @@ -302,37 +190,25 @@ lv_result_t lv_bin_decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_d decoder_data_t * decoder_data = get_decoder_data(dsc); decoder_data->decoded = adjusted; /*Now this new buffer need to be free'd on decoder close*/ } - dsc->decoded = adjusted; +#if LV_CACHE_DEF_SIZE > 0 + /*Add it to cache*/ - t = lv_tick_elaps(t); - lv_cache_lock(); - lv_cache_entry_t * cache = lv_cache_add(NULL, 0, decoder->cache_data_type, dsc->header.w * dsc->header.h * 4); - if(cache == NULL) { - lv_cache_unlock(); + lv_image_cache_data_t search_key; + search_key.src_type = dsc->src_type; + search_key.src = dsc->src; + search_key.slot.size = dsc->decoded->data_size; + + lv_cache_entry_t * cache_entry = lv_image_decoder_add_to_cache(decoder, &search_key, dsc->decoded, dsc->user_data); + if(cache_entry == NULL) { free_decoder_data(dsc); return LV_RESULT_INVALID; } + dsc->cache_entry = cache_entry; +#endif - cache->weight = t; - cache->data = dsc->decoded; - cache->invalidate_cb = cache_invalidate_cb; - if(dsc->src_type == LV_IMAGE_SRC_FILE) { - cache->src = lv_strdup(dsc->src); - cache->src_type = LV_CACHE_SRC_TYPE_PATH; - } - else { - cache->src_type = LV_CACHE_SRC_TYPE_POINTER; - cache->src = dsc->src; - } - - cache->user_data = dsc->user_data; /*Need to free data on cache invalidate instead of decoder_close*/ - dsc->decoded = lv_cache_get_data(cache); /*@note: Must get from cache to increase reference count.*/ - dsc->cache_entry = cache; - - lv_cache_unlock(); - return res; + return LV_RESULT_OK; } void lv_bin_decoder_close(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc) @@ -347,9 +223,7 @@ void lv_bin_decoder_close(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * if(dsc->cache_entry) { /*Decoded data is in cache, release it from cache's callback*/ - lv_cache_lock(); - lv_cache_release(dsc->cache_entry); - lv_cache_unlock(); + lv_cache_release(dsc->cache, dsc->cache_entry, NULL); } else { /*Data not in cache, free the memory manually*/ @@ -1025,42 +899,130 @@ static lv_result_t decompress_image(lv_image_decoder_dsc_t * dsc, const lv_image return LV_RESULT_OK; } -static lv_result_t try_cache(lv_image_decoder_dsc_t * dsc) +static bool bin_decoder_decode_data(lv_image_decoder_dsc_t * dsc) { - lv_cache_lock(); - if(dsc->src_type == LV_IMAGE_SRC_FILE) { - const char * fn = dsc->src; + lv_image_decoder_t * decoder = dsc->decoder; - lv_cache_entry_t * cache = lv_cache_find_by_src(NULL, fn, LV_CACHE_SRC_TYPE_PATH); - if(cache) { - dsc->decoded = lv_cache_get_data(cache); - dsc->cache_entry = cache; /*Save the cache to release it in decoder_close*/ - lv_cache_unlock(); - return LV_RESULT_OK; + lv_fs_res_t res = LV_RESULT_INVALID; + + /*Open the file if it's a file*/ + if(dsc->src_type == LV_IMAGE_SRC_FILE) { + /*Support only "*.bin" files*/ + if(lv_strcmp(lv_fs_get_ext(dsc->src), "bin")) return false; + + /*If the file was open successfully save the file descriptor*/ + decoder_data_t * decoder_data = get_decoder_data(dsc); + if(decoder_data == NULL) { + return false; } + + dsc->user_data = decoder_data; + lv_fs_file_t * f = lv_malloc(sizeof(*f)); + if(f == NULL) { + free_decoder_data(dsc); + return false; + } + + res = lv_fs_open(f, dsc->src, LV_FS_MODE_RD); + if(res != LV_FS_RES_OK) { + LV_LOG_WARN("Open file failed: %d", res); + lv_free(f); + free_decoder_data(dsc); + return false; + } + + decoder_data->f = f; /*Now free_decoder_data will take care of the file*/ + + lv_color_format_t cf = dsc->header.cf; + + if(dsc->header.flags & LV_IMAGE_FLAGS_COMPRESSED) { + res = decode_compressed(decoder, dsc); + } + else if(LV_COLOR_FORMAT_IS_INDEXED(cf)) { + /*Palette for indexed image and whole image of A8 image are always loaded to RAM for simplicity*/ + res = decode_indexed(decoder, dsc); + } + else if(LV_COLOR_FORMAT_IS_ALPHA_ONLY(cf)) { + res = decode_alpha_only(decoder, dsc); + } +#if LV_BIN_DECODER_RAM_LOAD + else if(cf == LV_COLOR_FORMAT_ARGB8888 \ + || cf == LV_COLOR_FORMAT_XRGB8888 \ + || cf == LV_COLOR_FORMAT_RGB888 \ + || cf == LV_COLOR_FORMAT_RGB565 \ + || cf == LV_COLOR_FORMAT_RGB565A8) { + res = decode_rgb(decoder, dsc); + } +#else + else { + /* decode them in get_area_cb */ + res = LV_RESULT_OK; + } +#endif } else if(dsc->src_type == LV_IMAGE_SRC_VARIABLE) { - const lv_image_dsc_t * img_dsc = dsc->src; + /*The variables should have valid data*/ + lv_image_dsc_t * image = (lv_image_dsc_t *)dsc->src; + if(image->data == NULL) { + return false; + } - lv_cache_entry_t * cache = lv_cache_find_by_src(NULL, img_dsc, LV_CACHE_SRC_TYPE_POINTER); - if(cache) { - dsc->decoded = lv_cache_get_data(cache); - dsc->cache_entry = cache; /*Save the cache to release it in decoder_close*/ - lv_cache_unlock(); - return LV_RESULT_OK; + lv_color_format_t cf = image->header.cf; + if(dsc->header.flags & LV_IMAGE_FLAGS_COMPRESSED) { + res = decode_compressed(decoder, dsc); + } + else if(LV_COLOR_FORMAT_IS_INDEXED(cf)) { + /*Need decoder data to store converted image*/ + decoder_data_t * decoder_data = get_decoder_data(dsc); + if(decoder_data == NULL) { + return false; + } + + res = decode_indexed(decoder, dsc); + } + else if(LV_COLOR_FORMAT_IS_ALPHA_ONLY(cf)) { + /*Alpha only image will need decoder data to store pointer to decoded image, to free it when decoder closes*/ + decoder_data_t * decoder_data = get_decoder_data(dsc); + if(decoder_data == NULL) { + return false; + } + + res = decode_alpha_only(decoder, dsc); + } + else { + /*In case of uncompressed formats the image stored in the ROM/RAM. + *So simply give its pointer*/ + + decoder_data_t * decoder_data = get_decoder_data(dsc); + lv_draw_buf_t * decoded = &decoder_data->c_array; + dsc->decoded = decoded; + lv_draw_buf_from_image(decoded, image); + + if(decoded->header.stride == 0) { + /*Use the auto calculated value from decoder_info callback*/ + decoded->header.stride = dsc->header.stride; + } + + res = LV_RESULT_OK; } } - lv_cache_unlock(); - return LV_RESULT_INVALID; + if(res != LV_RESULT_OK) { + free_decoder_data(dsc); + return false; + } + + return true; } -static void cache_invalidate_cb(lv_cache_entry_t * entry) +static void bin_decoder_cache_free_cb(lv_image_cache_data_t * cached_data, void * user_data) { + LV_UNUSED(user_data); /*Unused*/ + lv_image_decoder_dsc_t fake = { 0 }; - fake.user_data = entry->user_data; + fake.user_data = cached_data->user_data; free_decoder_data(&fake); - if(entry->src_type == LV_CACHE_SRC_TYPE_PATH) lv_free((void *)entry->src); + if(cached_data->src_type == LV_IMAGE_SRC_FILE) lv_free((void *)cached_data->src); } diff --git a/src/libs/ffmpeg/lv_ffmpeg.c b/src/libs/ffmpeg/lv_ffmpeg.c index 497a932bc8..d7e2b31c0c 100644 --- a/src/libs/ffmpeg/lv_ffmpeg.c +++ b/src/libs/ffmpeg/lv_ffmpeg.c @@ -800,9 +800,7 @@ static void lv_ffmpeg_player_frame_update_cb(lv_timer_t * timer) return; } - lv_cache_lock(); - lv_cache_invalidate_by_src(lv_image_get_src(obj), LV_CACHE_SRC_TYPE_POINTER); - lv_cache_unlock(); + lv_image_cache_drop(lv_image_get_src(obj)); lv_obj_invalidate(obj); } @@ -839,9 +837,7 @@ static void lv_ffmpeg_player_destructor(const lv_obj_class_t * class_p, player->timer = NULL; } - lv_cache_lock(); - lv_cache_invalidate_by_src(lv_image_get_src(obj), LV_CACHE_SRC_TYPE_POINTER); - lv_cache_unlock(); + lv_image_cache_drop(lv_image_get_src(obj)); ffmpeg_close(player->ffmpeg_ctx); player->ffmpeg_ctx = NULL; diff --git a/src/libs/freetype/lv_freetype_outline.c b/src/libs/freetype/lv_freetype_outline.c index 5c3a4e7553..1d84a8874a 100755 --- a/src/libs/freetype/lv_freetype_outline.c +++ b/src/libs/freetype/lv_freetype_outline.c @@ -49,11 +49,11 @@ struct _lv_freetype_cache_node_t { FT_Face face; /*glyph outline cache*/ - lv_lru_rb_t * glyph_outline_lru; + lv_cache_t * glyph_outline_cache; int outline_cnt; /*glyph size cache*/ - lv_lru_rb_t * glyph_dsc_lru; + lv_cache_t * glyph_dsc_cache; int dsc_cnt; }; @@ -82,14 +82,14 @@ static lv_freetype_outline_node_t * lv_freetype_outline_lookup(lv_freetype_font_ /*glyph dsc cache lru callbacks*/ static bool freetype_glyph_outline_create_cb(lv_freetype_outline_node_t * node, lv_freetype_font_dsc_t * dsc); static void freetype_glyph_outline_free_cb(lv_freetype_outline_node_t * node, lv_freetype_font_dsc_t * dsc); -static lv_lru_rb_compare_res_t freetype_glyph_outline_cmp_cb(const lv_freetype_outline_node_t * node_a, - const lv_freetype_outline_node_t * node_b); +static lv_cache_compare_res_t freetype_glyph_outline_cmp_cb(const lv_freetype_outline_node_t * node_a, + const lv_freetype_outline_node_t * node_b); /*glyph dsc cache lru callbacks*/ static bool freetype_glyph_dsc_create_cb(lv_freetype_glyph_dsc_node_t * glyph_dsc_node, lv_freetype_font_dsc_t * dsc); static void freetype_glyph_dsc_free_cb(lv_freetype_glyph_dsc_node_t * glyph_dsc_node, lv_freetype_font_dsc_t * dsc); -static lv_lru_rb_compare_res_t freetype_glyph_dsc_cmp_cb(const lv_freetype_glyph_dsc_node_t * node_a, - const lv_freetype_glyph_dsc_node_t * node_b); +static lv_cache_compare_res_t freetype_glyph_dsc_cmp_cb(const lv_freetype_glyph_dsc_node_t * node_a, + const lv_freetype_glyph_dsc_node_t * node_b); /********************** * STATIC VARIABLES @@ -266,14 +266,23 @@ static lv_freetype_cache_node_t * lv_freetype_cache_node_lookup(lv_freetype_cont cache->ref_cnt = 1; cache->cache_context = cache_context; - cache->glyph_dsc_lru = lv_lru_rb_create(sizeof(lv_freetype_glyph_dsc_node_t), LV_FREETYPE_GLYPH_DSC_CACHE_SIZE, - (lv_lru_rb_compare_cb_t)freetype_glyph_dsc_cmp_cb, - (lv_lru_rb_create_cb_t)freetype_glyph_dsc_create_cb, - (lv_lru_rb_free_cb_t)freetype_glyph_dsc_free_cb); - cache->glyph_outline_lru = lv_lru_rb_create(sizeof(lv_freetype_outline_node_t), LV_FREETYPE_CACHE_FT_OUTLINES, - (lv_lru_rb_compare_cb_t)freetype_glyph_outline_cmp_cb, - (lv_lru_rb_create_cb_t)freetype_glyph_outline_create_cb, - (lv_lru_rb_free_cb_t)freetype_glyph_outline_free_cb); + lv_cache_ops_t glyph_dsc_cache_ops = { + .create_cb = (lv_cache_create_cb_t)freetype_glyph_dsc_create_cb, + .free_cb = (lv_cache_free_cb_t)freetype_glyph_dsc_free_cb, + .compare_cb = (lv_cache_compare_cb_t)freetype_glyph_dsc_cmp_cb, + }; + lv_cache_ops_t glyph_outline_cache_ops = { + .create_cb = (lv_cache_create_cb_t)freetype_glyph_outline_create_cb, + .free_cb = (lv_cache_free_cb_t)freetype_glyph_outline_free_cb, + .compare_cb = (lv_cache_compare_cb_t)freetype_glyph_outline_cmp_cb, + }; + + cache->glyph_dsc_cache = lv_cache_create(&lv_cache_class_lru_rb, sizeof(lv_freetype_glyph_dsc_node_t), + LV_FREETYPE_GLYPH_DSC_CACHE_SIZE, + glyph_dsc_cache_ops); + cache->glyph_outline_cache = lv_cache_create(&lv_cache_class_lru_rb_count, sizeof(lv_freetype_outline_node_t), + LV_FREETYPE_CACHE_FT_OUTLINES, + glyph_outline_cache_ops); LV_LOG_INFO("outline cache(name: %s, style: 0x%x) create %p, ref_cnt = %d", pathname, style, cache, cache->ref_cnt); @@ -303,8 +312,8 @@ static void lv_freetype_cache_node_drop(lv_freetype_font_dsc_t * dsc) lv_ll_t * cache_ll = &cache_node->cache_context->cache_ll; _lv_ll_remove(cache_ll, cache_node); - lv_lru_rb_destroy(cache_node->glyph_dsc_lru, dsc); - lv_lru_rb_destroy(cache_node->glyph_outline_lru, dsc); + lv_cache_destroy(cache_node->glyph_dsc_cache, dsc); + lv_cache_destroy(cache_node->glyph_outline_cache, dsc); lv_free(cache_node); } @@ -352,8 +361,8 @@ static void freetype_glyph_dsc_free_cb(lv_freetype_glyph_dsc_node_t * glyph_dsc_ LV_LOG_INFO("cnt = %d", --dsc->cache_node->dsc_cnt); } -static lv_lru_rb_compare_res_t freetype_glyph_dsc_cmp_cb(const lv_freetype_glyph_dsc_node_t * node_a, - const lv_freetype_glyph_dsc_node_t * node_b) +static lv_cache_compare_res_t freetype_glyph_dsc_cmp_cb(const lv_freetype_glyph_dsc_node_t * node_a, + const lv_freetype_glyph_dsc_node_t * node_b) { if(node_a->glyph_index != node_b->glyph_index) return (node_a->glyph_index > node_b->glyph_index) ? 1 : -1; @@ -394,10 +403,11 @@ static bool freetype_get_glyph_dsc_cb(const lv_font_t * font, tmp_node.glyph_index = glyph_index; tmp_node.size = dsc->size; - lv_freetype_glyph_dsc_node_t * new_node = lv_lru_rb_get_or_create(cache_node->glyph_dsc_lru, &tmp_node, dsc); - if(!new_node) { + lv_cache_entry_t * entry = lv_cache_acquire_or_create(cache_node->glyph_dsc_cache, &tmp_node, dsc); + if(entry == NULL) { return false; } + lv_freetype_glyph_dsc_node_t * new_node = lv_cache_entry_get_data(entry); *dsc_out = new_node->glyph_dsc; if((dsc->style & LV_FREETYPE_FONT_STYLE_ITALIC) && (unicode_letter_next == '\0')) { @@ -437,8 +447,8 @@ static void freetype_glyph_outline_free_cb(lv_freetype_outline_node_t * node, lv LV_LOG_INFO("cnt = %d", --dsc->cache_node->outline_cnt); } -static lv_lru_rb_compare_res_t freetype_glyph_outline_cmp_cb(const lv_freetype_outline_node_t * node_a, - const lv_freetype_outline_node_t * node_b) +static lv_cache_compare_res_t freetype_glyph_outline_cmp_cb(const lv_freetype_outline_node_t * node_a, + const lv_freetype_outline_node_t * node_b) { if(node_a->glyph_index == node_b->glyph_index) { return 0; @@ -466,11 +476,12 @@ static lv_freetype_outline_node_t * lv_freetype_outline_lookup(lv_freetype_font_ lv_freetype_outline_node_t tmp_node; tmp_node.glyph_index = glyph_index; - lv_freetype_outline_node_t * new_node = lv_lru_rb_get_or_create(cache_node->glyph_outline_lru, &tmp_node, dsc); - if(!new_node) { + lv_cache_entry_t * entry = lv_cache_acquire_or_create(cache_node->glyph_outline_cache, &tmp_node, dsc); + if(!entry) { LV_LOG_ERROR("glyph outline lookup failed for glyph_index = %u", glyph_index); return NULL; } + lv_freetype_outline_node_t * new_node = lv_cache_entry_get_data(entry); return new_node; } diff --git a/src/libs/gif/lv_gif.c b/src/libs/gif/lv_gif.c index c4dd4248c7..1ab48e30f6 100644 --- a/src/libs/gif/lv_gif.c +++ b/src/libs/gif/lv_gif.c @@ -62,9 +62,7 @@ void lv_gif_set_src(lv_obj_t * obj, const void * src) /*Close previous gif if any*/ if(gifobj->gif) { - lv_cache_lock(); - lv_cache_invalidate_by_src(lv_image_get_src(obj), LV_CACHE_SRC_TYPE_POINTER); - lv_cache_unlock(); + lv_image_cache_drop(lv_image_get_src(obj)); gd_close_gif(gifobj->gif); gifobj->gif = NULL; @@ -150,9 +148,7 @@ 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_cache_lock(); - lv_cache_invalidate_by_src(lv_image_get_src(obj), LV_CACHE_SRC_TYPE_POINTER); - lv_cache_unlock(); + lv_image_cache_drop(lv_image_get_src(obj)); if(gifobj->gif) gd_close_gif(gifobj->gif); @@ -178,9 +174,7 @@ static void next_frame_task_cb(lv_timer_t * t) gd_render_frame(gifobj->gif, (uint8_t *)gifobj->imgdsc.data); - lv_cache_lock(); - lv_cache_invalidate_by_src(lv_image_get_src(obj), LV_CACHE_SRC_TYPE_POINTER); - lv_cache_unlock(); + lv_image_cache_drop(lv_image_get_src(obj)); lv_obj_invalidate(obj); } diff --git a/src/libs/libjpeg_turbo/lv_libjpeg_turbo.c b/src/libs/libjpeg_turbo/lv_libjpeg_turbo.c index 4704852896..2c9f8f95bf 100644 --- a/src/libs/libjpeg_turbo/lv_libjpeg_turbo.c +++ b/src/libs/libjpeg_turbo/lv_libjpeg_turbo.c @@ -39,9 +39,7 @@ static void decoder_close(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * static lv_draw_buf_t * decode_jpeg_file(const char * filename); static bool get_jpeg_size(const char * filename, uint32_t * width, uint32_t * height); static void error_exit(j_common_ptr cinfo); -static lv_result_t try_cache(lv_image_decoder_dsc_t * dsc); -static void cache_invalidate_cb(lv_cache_entry_t * entry); - +static void jpeg_decoder_cache_free_cb(lv_image_cache_data_t * cached_data, void * user_data); /********************** * STATIC VARIABLES **********************/ @@ -63,7 +61,7 @@ void lv_libjpeg_turbo_init(void) lv_image_decoder_set_info_cb(dec, decoder_info); lv_image_decoder_set_open_cb(dec, decoder_open); lv_image_decoder_set_close_cb(dec, decoder_close); - dec->cache_data_type = lv_cache_register_data_type(); + lv_image_decoder_set_cache_free_cb(dec, (lv_cache_free_cb_t)jpeg_decoder_cache_free_cb); } void lv_libjpeg_turbo_deinit(void) @@ -153,44 +151,31 @@ static lv_result_t decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_d LV_UNUSED(decoder); /*Unused*/ LV_UNUSED(args); /*Unused*/ - /*Check the cache first*/ - if(try_cache(dsc) == LV_RESULT_OK) return LV_RESULT_OK; - /*If it's a JPEG file...*/ if(dsc->src_type == LV_IMAGE_SRC_FILE) { const char * fn = dsc->src; - uint32_t t = lv_tick_get(); lv_draw_buf_t * decoded = decode_jpeg_file(fn); if(decoded == NULL) { LV_LOG_WARN("decode jpeg file failed"); return LV_RESULT_INVALID; } - t = lv_tick_elaps(t); - lv_cache_lock(); - lv_cache_entry_t * cache = lv_cache_add(decoded, decoded->data_size, decoder->cache_data_type, - decoded->data_size); - if(cache == NULL) { - lv_cache_unlock(); + dsc->decoded = decoded; + +#if LV_CACHE_DEF_SIZE > 0 + lv_image_cache_data_t search_key; + search_key.src_type = dsc->src_type; + search_key.src = dsc->src; + search_key.slot.size = decoded->data_size; + + lv_cache_entry_t * entry = lv_image_decoder_add_to_cache(decoder, &search_key, decoded, NULL); + + if(entry == NULL) { lv_draw_buf_destroy(decoded); return LV_RESULT_INVALID; } - - cache->weight = t; - cache->invalidate_cb = cache_invalidate_cb; - if(dsc->src_type == LV_IMAGE_SRC_FILE) { - cache->src = lv_strdup(dsc->src); - cache->src_type = LV_CACHE_SRC_TYPE_PATH; - } - else { - cache->src_type = LV_CACHE_SRC_TYPE_POINTER; - cache->src = dsc->src; - } - - dsc->decoded = lv_cache_get_data(cache); - dsc->cache_entry = cache; - - lv_cache_unlock(); + dsc->cache_entry = entry; +#endif return LV_RESULT_OK; /*If not returned earlier then it failed*/ } @@ -203,28 +188,12 @@ static lv_result_t decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_d static void decoder_close(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc) { LV_UNUSED(decoder); /*Unused*/ - lv_cache_lock(); - lv_cache_release(dsc->cache_entry); - lv_cache_unlock(); -} -static lv_result_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_by_src(NULL, fn, LV_CACHE_SRC_TYPE_PATH); - if(cache) { - dsc->decoded = lv_cache_get_data(cache); - dsc->cache_entry = cache; /*Save the cache to release it in decoder_close*/ - lv_cache_unlock(); - return LV_RESULT_OK; - } - } - - lv_cache_unlock(); - return LV_RESULT_INVALID; +#if LV_CACHE_DEF_SIZE > 0 + lv_cache_release(dsc->cache, dsc->cache_entry, NULL); +#else + lv_draw_buf_destroy((lv_draw_buf_t *)dsc->decoded); +#endif } static uint8_t * alloc_file(const char * filename, uint32_t * size) @@ -482,10 +451,12 @@ static void error_exit(j_common_ptr cinfo) longjmp(myerr->jb, 1); } -static void cache_invalidate_cb(lv_cache_entry_t * entry) +static void jpeg_decoder_cache_free_cb(lv_image_cache_data_t * cached_data, void * user_data) { - if(entry->src_type == LV_CACHE_SRC_TYPE_PATH) lv_free((void *)entry->src); - lv_draw_buf_destroy((lv_draw_buf_t *)entry->data); + LV_UNUSED(user_data); + + if(cached_data->src_type == LV_IMAGE_SRC_FILE) lv_free((void *)cached_data->src); + lv_draw_buf_destroy((lv_draw_buf_t *)cached_data->decoded); } #endif /*LV_USE_LIBJPEG_TURBO*/ diff --git a/src/libs/libpng/lv_libpng.c b/src/libs/libpng/lv_libpng.c index 3876ceca47..8c3802e9e0 100644 --- a/src/libs/libpng/lv_libpng.c +++ b/src/libs/libpng/lv_libpng.c @@ -28,9 +28,8 @@ static lv_result_t decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_d const lv_image_decoder_args_t * args); static void decoder_close(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc); static lv_draw_buf_t * decode_png_file(const char * filename); -static lv_result_t try_cache(lv_image_decoder_dsc_t * dsc); -static void cache_invalidate_cb(lv_cache_entry_t * entry); +static void png_decoder_cache_free_cb(lv_image_cache_data_t * cached_data, void * user_data); /********************** * STATIC VARIABLES **********************/ @@ -52,7 +51,7 @@ void lv_libpng_init(void) lv_image_decoder_set_info_cb(dec, decoder_info); lv_image_decoder_set_open_cb(dec, decoder_open); lv_image_decoder_set_close_cb(dec, decoder_close); - dec->cache_data_type = lv_cache_register_data_type(); + lv_image_decoder_set_cache_free_cb(dec, (lv_cache_free_cb_t)png_decoder_cache_free_cb); } void lv_libpng_deinit(void) @@ -128,13 +127,9 @@ static lv_result_t decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_d LV_UNUSED(decoder); /*Unused*/ LV_UNUSED(args); /*Unused*/ - /*Check the cache first*/ - if(try_cache(dsc) == LV_RESULT_OK) return LV_RESULT_OK; - /*If it's a PNG file...*/ if(dsc->src_type == LV_IMAGE_SRC_FILE) { const char * fn = dsc->src; - uint32_t t = lv_tick_get(); lv_draw_buf_t * decoded = decode_png_file(fn); if(decoded == NULL) { return LV_RESULT_INVALID; @@ -156,31 +151,22 @@ static lv_result_t decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_d } } - t = lv_tick_elaps(t); + dsc->decoded = decoded; - lv_cache_lock(); - lv_cache_entry_t * cache = lv_cache_add(decoded, 0, decoder->cache_data_type, decoded->data_size); - if(cache == NULL) { - lv_cache_unlock(); +#if LV_CACHE_DEF_SIZE > 0 + lv_image_cache_data_t search_key; + search_key.src_type = dsc->src_type; + search_key.src = dsc->src; + search_key.slot.size = decoded->data_size; + + lv_cache_entry_t * entry = lv_image_decoder_add_to_cache(decoder, &search_key, decoded, NULL); + + if(entry == NULL) { lv_draw_buf_destroy(decoded); return LV_RESULT_INVALID; } - - cache->weight = t; - cache->invalidate_cb = cache_invalidate_cb; - if(dsc->src_type == LV_IMAGE_SRC_FILE) { - cache->src = lv_strdup(dsc->src); - cache->src_type = LV_CACHE_SRC_TYPE_PATH; - } - else { - cache->src_type = LV_CACHE_SRC_TYPE_POINTER; - cache->src = dsc->src; - } - - dsc->decoded = lv_cache_get_data(cache); - dsc->cache_entry = cache; - - lv_cache_unlock(); + dsc->cache_entry = entry; +#endif return LV_RESULT_OK; /*The image is fully decoded. Return with its pointer*/ } @@ -194,28 +180,11 @@ static void decoder_close(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * { LV_UNUSED(decoder); /*Unused*/ - lv_cache_lock(); - lv_cache_release(dsc->cache_entry); - lv_cache_unlock(); -} - -static lv_result_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_by_src(NULL, fn, LV_CACHE_SRC_TYPE_PATH); - if(cache) { - dsc->decoded = lv_cache_get_data(cache); - dsc->cache_entry = cache; /*Save the cache to release it in decoder_close*/ - lv_cache_unlock(); - return LV_RESULT_OK; - } - } - - lv_cache_unlock(); - return LV_RESULT_INVALID; +#if LV_CACHE_DEF_SIZE > 0 + lv_cache_release(dsc->cache, dsc->cache_entry, NULL); +#else + lv_draw_buf_destroy((lv_draw_buf_t *)dsc->decoded); +#endif } static uint8_t * alloc_file(const char * filename, uint32_t * size) @@ -323,10 +292,12 @@ static lv_draw_buf_t * decode_png_file(const char * filename) return decoded; } -static void cache_invalidate_cb(lv_cache_entry_t * entry) +static void png_decoder_cache_free_cb(lv_image_cache_data_t * cached_data, void * user_data) { - lv_free((void *)entry->src); - lv_draw_buf_destroy((lv_draw_buf_t *)entry->data); + LV_UNUSED(user_data); + + if(cached_data->src_type == LV_IMAGE_SRC_FILE) lv_free((void *)cached_data->src); + lv_draw_buf_destroy((lv_draw_buf_t *)cached_data->decoded); } #endif /*LV_USE_LIBPNG*/ diff --git a/src/libs/lodepng/lv_lodepng.c b/src/libs/lodepng/lv_lodepng.c index b97896150c..09ea619ff0 100644 --- a/src/libs/lodepng/lv_lodepng.c +++ b/src/libs/lodepng/lv_lodepng.c @@ -30,9 +30,7 @@ static lv_result_t decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_d 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 lv_draw_buf_t * decode_png_data(const void * png_data, size_t png_data_size); -static lv_result_t try_cache(lv_image_decoder_dsc_t * dsc); -static void cache_invalidate_cb(lv_cache_entry_t * entry); - +static void lodepng_decoder_cache_free_cb(lv_image_cache_data_t * cached_data, void * user_data); /********************** * STATIC VARIABLES **********************/ @@ -54,7 +52,7 @@ void lv_lodepng_init(void) lv_image_decoder_set_info_cb(dec, decoder_info); lv_image_decoder_set_open_cb(dec, decoder_open); lv_image_decoder_set_close_cb(dec, decoder_close); - dec->cache_data_type = lv_cache_register_data_type(); + lv_image_decoder_set_cache_free_cb(dec, (lv_cache_free_cb_t)lodepng_decoder_cache_free_cb); } void lv_lodepng_deinit(void) @@ -158,9 +156,6 @@ static lv_result_t decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_d LV_UNUSED(decoder); LV_UNUSED(args); - /*Check the cache first*/ - if(try_cache(dsc) == LV_RESULT_OK) return LV_RESULT_OK; - const uint8_t * png_data = NULL; size_t png_data_size = 0; if(dsc->src_type == LV_IMAGE_SRC_FILE) { @@ -186,14 +181,6 @@ static lv_result_t decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_d return LV_RESULT_INVALID; } - lv_cache_lock(); - lv_cache_entry_t * cache = lv_cache_add(NULL, 0, decoder->cache_data_type, dsc->header.w * dsc->header.h * 4); - if(cache == NULL) { - lv_cache_unlock(); - return LV_RESULT_INVALID; - } - - uint32_t t = lv_tick_get(); lv_draw_buf_t * decoded = decode_png_data(png_data, png_data_size); /*Stride check and adjustment accordingly*/ if(args && args->stride_align) { @@ -211,24 +198,26 @@ static lv_result_t decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_d } } - t = lv_tick_elaps(t); - cache->weight = t; - cache->data = decoded; - cache->invalidate_cb = cache_invalidate_cb; if(dsc->src_type == LV_IMAGE_SRC_FILE) { - cache->src = lv_strdup(dsc->src); - cache->src_type = LV_CACHE_SRC_TYPE_PATH; lv_free((void *)png_data); } - else { - cache->src_type = LV_CACHE_SRC_TYPE_POINTER; - cache->src = dsc->src; + + dsc->decoded = decoded; + +#if LV_CACHE_DEF_SIZE > 0 + lv_image_cache_data_t search_key; + search_key.src_type = dsc->src_type; + search_key.src = dsc->src; + search_key.slot.size = decoded->data_size; + + lv_cache_entry_t * entry = lv_image_decoder_add_to_cache(decoder, &search_key, decoded, NULL); + + if(entry == NULL) { + return LV_RESULT_INVALID; } + dsc->cache_entry = entry; +#endif - dsc->decoded = lv_cache_get_data(cache); - dsc->cache_entry = cache; - - lv_cache_unlock(); return LV_RESULT_OK; /*If not returned earlier then it failed*/ } @@ -242,40 +231,11 @@ static void decoder_close(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * { LV_UNUSED(decoder); - lv_cache_lock(); - lv_cache_release(dsc->cache_entry); - lv_cache_unlock(); -} - -static lv_result_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_by_src(NULL, fn, LV_CACHE_SRC_TYPE_PATH); - if(cache) { - dsc->decoded = lv_cache_get_data(cache); - dsc->cache_entry = cache; /*Save the cache to release it in decoder_close*/ - lv_cache_unlock(); - return LV_RESULT_OK; - } - } - - else if(dsc->src_type == LV_IMAGE_SRC_VARIABLE) { - const lv_image_dsc_t * img_dsc = dsc->src; - - lv_cache_entry_t * cache = lv_cache_find_by_src(NULL, img_dsc, LV_CACHE_SRC_TYPE_POINTER); - if(cache) { - dsc->decoded = lv_cache_get_data(cache); - dsc->cache_entry = cache; /*Save the cache to release it in decoder_close*/ - lv_cache_unlock(); - return LV_RESULT_OK; - } - } - - lv_cache_unlock(); - return LV_RESULT_INVALID; +#if LV_CACHE_DEF_SIZE > 0 + lv_cache_release(dsc->cache, dsc->cache_entry, NULL); +#else + lv_draw_buf_destroy((lv_draw_buf_t *)dsc->decoded); +#endif } static lv_draw_buf_t * decode_png_data(const void * png_data, size_t png_data_size) @@ -314,10 +274,12 @@ static void convert_color_depth(uint8_t * img_p, uint32_t px_cnt) } } -static void cache_invalidate_cb(lv_cache_entry_t * entry) +static void lodepng_decoder_cache_free_cb(lv_image_cache_data_t * cached_data, void * user_data) { - if(entry->src_type == LV_CACHE_SRC_TYPE_PATH) lv_free((void *)entry->src); - lv_draw_buf_destroy((lv_draw_buf_t *)entry->data); + LV_UNUSED(user_data); + + if(cached_data->src_type == LV_IMAGE_SRC_FILE) lv_free((void *)cached_data->src); + lv_draw_buf_destroy((lv_draw_buf_t *)cached_data->decoded); } #endif /*LV_USE_LODEPNG*/ diff --git a/src/libs/qrcode/lv_qrcode.c b/src/libs/qrcode/lv_qrcode.c index 37adab80ff..26383bc630 100644 --- a/src/libs/qrcode/lv_qrcode.c +++ b/src/libs/qrcode/lv_qrcode.c @@ -221,7 +221,9 @@ static void lv_qrcode_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj) lv_draw_buf_t * draw_buf = lv_canvas_get_draw_buf(obj); if(draw_buf == NULL) return; + lv_image_cache_drop(draw_buf); + /*@fixme destroy buffer in cache free_cb.*/ lv_draw_buf_destroy(draw_buf); } diff --git a/src/libs/rlottie/lv_rlottie.c b/src/libs/rlottie/lv_rlottie.c index 19ce8e09dc..33b671f1f6 100644 --- a/src/libs/rlottie/lv_rlottie.c +++ b/src/libs/rlottie/lv_rlottie.c @@ -174,9 +174,7 @@ static void lv_rlottie_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj rlottie->dest_frame = 0; } - lv_cache_lock(); - lv_cache_invalidate_by_src(&rlottie->imgdsc, LV_CACHE_SRC_TYPE_POINTER); - lv_cache_unlock(); + lv_image_cache_drop(&rlottie->imgdsc); if(rlottie->allocated_buf) { lv_free(rlottie->allocated_buf); diff --git a/src/libs/tiny_ttf/lv_tiny_ttf.c b/src/libs/tiny_ttf/lv_tiny_ttf.c index 214cbd6da9..b10107fb1c 100644 --- a/src/libs/tiny_ttf/lv_tiny_ttf.c +++ b/src/libs/tiny_ttf/lv_tiny_ttf.c @@ -1,6 +1,8 @@ #include "lv_tiny_ttf.h" #if LV_USE_TINY_TTF #include +#include "../../core/lv_global.h" +#include "lv_tiny_ttf.h" #define STB_RECT_PACK_IMPLEMENTATION #define STBRP_STATIC @@ -12,6 +14,8 @@ #define STBTT_malloc(x, u) ((void)(u), lv_malloc(x)) #define STBTT_free(x, u) ((void)(u), lv_free(x)) +#define tiny_ttf_cache LV_GLOBAL_DEFAULT()->tiny_ttf_cache + #if LV_TINY_TTF_FILE_SUPPORT != 0 /* a hydra stream that can be in memory or from a file*/ typedef struct ttf_cb_stream { @@ -72,9 +76,19 @@ typedef struct ttf_font_desc { int descent; } ttf_font_desc_t; -typedef struct ttf_cache_entry { +typedef struct _tiny_ttf_cache_data_t { + lv_font_t * font; + uint32_t unicode; + uint32_t size; + uint8_t * buffer; -} ttf_cache_entry_t; + uint32_t buffer_size; +} tiny_ttf_cache_data_t; + +static bool tiny_ttf_cache_create_cb(tiny_ttf_cache_data_t * node, void * user_data); +static void tiny_ttf_cache_free_cb(tiny_ttf_cache_data_t * node, void * user_data); +static lv_cache_compare_res_t tiny_ttf_cache_compare_cb(const tiny_ttf_cache_data_t * lhs, + const tiny_ttf_cache_data_t * rhs); static bool ttf_get_glyph_dsc_cb(const lv_font_t * font, lv_font_glyph_dsc_t * dsc_out, uint32_t unicode_letter, uint32_t unicode_letter_next) @@ -121,73 +135,26 @@ static bool ttf_get_glyph_dsc_cb(const lv_font_t * font, lv_font_glyph_dsc_t * d return true; /*true: glyph found; false: glyph was not found*/ } -static void cache_invalidate_cb(lv_cache_entry_t * entry) -{ - lv_draw_buf_free((void *)entry->data); -} - static const uint8_t * ttf_get_glyph_bitmap_cb(const lv_font_t * font, uint32_t unicode_letter, uint8_t * bitmap_buf) { LV_UNUSED(bitmap_buf); - ttf_font_desc_t * dsc = (ttf_font_desc_t *)font->dsc; - const stbtt_fontinfo * info = (const stbtt_fontinfo *)&dsc->info; - int g1 = stbtt_FindGlyphIndex(info, (int)unicode_letter); - if(g1 == 0) { - /* Glyph not found */ - return NULL; - } - int x1, y1, x2, y2; - stbtt_GetGlyphBitmapBox(info, g1, dsc->scale, dsc->scale, &x1, &y1, &x2, &y2); - int w, h; - w = x2 - x1 + 1; - h = y2 - y1 + 1; - uint32_t stride = lv_draw_buf_width_to_stride(w, LV_COLOR_FORMAT_A8); - lv_cache_lock(); - uint32_t cp = unicode_letter; - lv_cache_entry_t * cache = lv_cache_find_by_src(NULL, font, LV_CACHE_SRC_TYPE_POINTER); - while(cache) { - if(cache->param1 == (int32_t)font->line_height && cache->param2 == (int32_t)cp) break; - cache = lv_cache_find_by_src(cache, font, LV_CACHE_SRC_TYPE_POINTER); - } - if(cache) { - uint8_t * buffer = (uint8_t *)lv_cache_get_data(cache); - lv_cache_release(cache); - lv_cache_unlock(); - return buffer; - } - size_t szb = h * stride; + tiny_ttf_cache_data_t search_key = { + .font = (lv_font_t *)font, + .unicode = unicode_letter, + .size = font->line_height, + }; - uint8_t * buffer = lv_draw_buf_malloc(szb, LV_COLOR_FORMAT_A8); - if(NULL == buffer) { - LV_LOG_ERROR("tiny_ttf: out of memory\n"); - lv_cache_unlock(); - return NULL; - } + lv_cache_entry_t * entry = lv_cache_acquire_or_create(tiny_ttf_cache, &search_key, (void *)font->dsc); - lv_cache_entry_t * entry = lv_cache_add(buffer, 0, LV_CACHE_DATA_TYPE_NOT_SET, szb); if(entry == NULL) { - lv_cache_unlock(); - lv_draw_buf_free(buffer); - LV_LOG_ERROR("tiny_ttf: cache not allocated\n"); + LV_LOG_ERROR("cache not allocated\n"); return NULL; } - /* This smells. We add the codepoint to the base pointer to get a key. */ - entry->src = font; - entry->src_type = LV_CACHE_SRC_TYPE_POINTER; - entry->param1 = font->line_height; - entry->param2 = cp; - entry->invalidate_cb = cache_invalidate_cb; - /*Just to increment life*/ - lv_cache_get_data(entry); - - memset(buffer, 0, szb); - stbtt_MakeGlyphBitmap(info, bitmap_buf, w, h, stride, dsc->scale, dsc->scale, g1); - lv_memcpy(buffer, bitmap_buf, stride * h); - lv_cache_release(entry); - lv_cache_unlock(); - return bitmap_buf; /*Or NULL if not found*/ + tiny_ttf_cache_data_t * cached_data = lv_cache_entry_get_data(entry); + lv_cache_release(tiny_ttf_cache, entry, NULL); + return cached_data->buffer; } static lv_result_t lv_tiny_ttf_create(lv_font_t * out_font, const char * path, const void * data, size_t data_size, @@ -282,9 +249,85 @@ void lv_tiny_ttf_destroy(lv_font_t * font) lv_fs_close(&ttf->file); } #endif + lv_cache_drop_all(tiny_ttf_cache, (void *)font->dsc); lv_free(ttf); + font->dsc = NULL; } } } +void lv_tiny_ttf_init(void) +{ + lv_cache_ops_t ops = { + .compare_cb = (lv_cache_compare_cb_t)tiny_ttf_cache_compare_cb, + .create_cb = (lv_cache_create_cb_t)tiny_ttf_cache_create_cb, + .free_cb = (lv_cache_free_cb_t)tiny_ttf_cache_free_cb, + }; + + tiny_ttf_cache = lv_cache_create(&lv_cache_class_lru_rb_count, sizeof(tiny_ttf_cache_data_t), 128, ops); +} + +void lv_tiny_ttf_deinit(void) +{ + lv_cache_destroy(tiny_ttf_cache, NULL); +} + +static bool tiny_ttf_cache_create_cb(tiny_ttf_cache_data_t * node, void * user_data) +{ + + ttf_font_desc_t * dsc = (ttf_font_desc_t *)user_data; + uint32_t unicode_letter = node->unicode; + + const stbtt_fontinfo * info = (const stbtt_fontinfo *)&dsc->info; + int g1 = stbtt_FindGlyphIndex(info, (int)unicode_letter); + if(g1 == 0) { + /* Glyph not found */ + return false; + } + int x1, y1, x2, y2; + stbtt_GetGlyphBitmapBox(info, g1, dsc->scale, dsc->scale, &x1, &y1, &x2, &y2); + int w, h; + w = x2 - x1 + 1; + h = y2 - y1 + 1; + uint32_t stride = lv_draw_buf_width_to_stride(w, LV_COLOR_FORMAT_A8); + size_t szb = h * stride; + + uint8_t * buffer = lv_draw_buf_malloc(szb, LV_COLOR_FORMAT_A8); + if(NULL == buffer) { + LV_LOG_ERROR("tiny_ttf: out of memory\n"); + return false; + } + + memset(buffer, 0, szb); + stbtt_MakeGlyphBitmap(info, buffer, w, h, stride, dsc->scale, dsc->scale, g1); + + node->buffer = buffer; + node->buffer_size = szb; + + return true; +} +static void tiny_ttf_cache_free_cb(tiny_ttf_cache_data_t * node, void * user_data) +{ + LV_UNUSED(user_data); + + lv_draw_buf_free(node->buffer); +} +static lv_cache_compare_res_t tiny_ttf_cache_compare_cb(const tiny_ttf_cache_data_t * lhs, + const tiny_ttf_cache_data_t * rhs) +{ + if(lhs->font != rhs->font) { + return lhs->font > rhs->font ? 1 : -1; + } + + if(lhs->unicode != rhs->unicode) { + return lhs->unicode > rhs->unicode ? 1 : -1; + } + + if(lhs->size != rhs->size) { + return lhs->size > rhs->size ? 1 : -1; + } + + return 0; +} + #endif diff --git a/src/libs/tiny_ttf/lv_tiny_ttf.h b/src/libs/tiny_ttf/lv_tiny_ttf.h index d9ee80d5ca..c4e3ba06f8 100644 --- a/src/libs/tiny_ttf/lv_tiny_ttf.h +++ b/src/libs/tiny_ttf/lv_tiny_ttf.h @@ -37,6 +37,10 @@ lv_result_t lv_tiny_ttf_create_file(lv_font_t * font, const char * path, int32_t lv_result_t lv_tiny_ttf_create_file_ex(lv_font_t * font, const char * path, int32_t font_size, size_t cache_size); #endif +void lv_tiny_ttf_init(void); + +void lv_tiny_ttf_deinit(void); + /* create a font from the specified data pointer with the specified line height.*/ lv_result_t lv_tiny_ttf_create_data(lv_font_t * font, const void * data, size_t data_size, int32_t font_size); diff --git a/src/lv_conf_internal.h b/src/lv_conf_internal.h index 13d3636033..7965b436f8 100644 --- a/src/lv_conf_internal.h +++ b/src/lv_conf_internal.h @@ -767,8 +767,8 @@ /*Default cache size in bytes. *Used by image decoders such as `lv_lodepng` 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.*/ + *If size is not set to 0, the decoder will fail to decode when the cache is full. + *If size is 0, the cache function is not enabled and the decoded mem will be released immediately after use.*/ #ifndef LV_CACHE_DEF_SIZE #ifdef CONFIG_LV_CACHE_DEF_SIZE #define LV_CACHE_DEF_SIZE CONFIG_LV_CACHE_DEF_SIZE diff --git a/src/lv_init.c b/src/lv_init.c index bc9a4f35b5..9d829cd583 100644 --- a/src/lv_init.c +++ b/src/lv_init.c @@ -22,8 +22,6 @@ #include "libs/lodepng/lv_lodepng.h" #include "libs/libpng/lv_libpng.h" #include "draw/lv_draw.h" -#include "misc/lv_cache.h" -#include "misc/lv_cache_builtin.h" #include "misc/lv_async.h" #include "misc/lv_fs.h" #if LV_USE_DRAW_VGLITE @@ -199,12 +197,6 @@ void lv_init(void) lv_draw_vg_lite_init(); #endif - _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 = "Á"; @@ -297,6 +289,10 @@ void lv_init(void) # endif #endif +#if LV_USE_TINY_TTF + lv_tiny_ttf_init(); +#endif + lv_initialized = true; LV_LOG_TRACE("finished"); @@ -334,6 +330,10 @@ void lv_deinit(void) lv_freetype_uninit(); #endif +#if LV_USE_TINY_TTF + lv_tiny_ttf_deinit(); +#endif + #if LV_USE_THEME_DEFAULT lv_theme_default_deinit(); #endif @@ -346,10 +346,6 @@ void lv_deinit(void) lv_theme_mono_deinit(); #endif - _lv_cache_builtin_deinit(); - - _lv_cache_deinit(); - _lv_image_decoder_deinit(); _lv_refr_deinit(); diff --git a/src/misc/cache/_lv_cache_lru_rb.c b/src/misc/cache/_lv_cache_lru_rb.c new file mode 100644 index 0000000000..18fcc5cc40 --- /dev/null +++ b/src/misc/cache/_lv_cache_lru_rb.c @@ -0,0 +1,404 @@ +/** +* @file _lv_cache_lru_rb.c +* +*/ + +/********************* + * INCLUDES + *********************/ +#include "_lv_cache_lru_rb.h" +#include "../../stdlib/lv_sprintf.h" +#include "../../stdlib/lv_string.h" +#include "../lv_ll.h" +#include "../lv_rb.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +typedef uint32_t (get_data_size_cb_t)(const void * data); + +struct _lv_lru_rb_t { + lv_cache_t cache; + + lv_rb_t rb; + lv_ll_t ll; + + get_data_size_cb_t * get_data_size_cb; +}; +typedef struct _lv_lru_rb_t lv_lru_rb_t_; +/********************** + * STATIC PROTOTYPES + **********************/ + +static void * alloc_cb(void); +static bool init_cnt_cb(lv_cache_t * cache); +static bool init_size_cb(lv_cache_t * cache); +static void destroy_cb(lv_cache_t * cache, void * user_data); + +static lv_cache_entry_t * get_cb(lv_cache_t * cache, const void * key, void * user_data); +static lv_cache_entry_t * add_cb(lv_cache_t * cache, const void * key, void * user_data); +static void remove_cb(lv_cache_t * cache, lv_cache_entry_t * entry, void * user_data); +static void drop_cb(lv_cache_t * cache, const void * key, void * user_data); +static void drop_all_cb(lv_cache_t * cache, void * user_data); + +static void * alloc_new_node(lv_lru_rb_t_ * lru, void * key, void * user_data); +inline static void ** get_lru_node(lv_lru_rb_t_ * lru, lv_rb_node_t * node); + +static uint32_t cnt_get_data_size_cb(const void * data); +static uint32_t size_get_data_size_cb(const void * data); + +/********************** + * GLOBAL VARIABLES + **********************/ +const lv_cache_class_t lv_cache_class_lru_rb_count = { + .alloc_cb = alloc_cb, + .init_cb = init_cnt_cb, + .destroy_cb = destroy_cb, + + .get_cb = get_cb, + .add_cb = add_cb, + .remove_cb = remove_cb, + .drop_cb = drop_cb, + .drop_all_cb = drop_all_cb +}; + +const lv_cache_class_t lv_cache_class_lru_rb_size = { + .alloc_cb = alloc_cb, + .init_cb = init_size_cb, + .destroy_cb = destroy_cb, + + .get_cb = get_cb, + .add_cb = add_cb, + .remove_cb = remove_cb, + .drop_cb = drop_cb, + .drop_all_cb = drop_all_cb +}; +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/********************** + * STATIC FUNCTIONS + **********************/ +static void * alloc_new_node(lv_lru_rb_t_ * lru, void * key, void * user_data) +{ + LV_UNUSED(user_data); + + LV_ASSERT_NULL(lru); + LV_ASSERT_NULL(key); + + if(lru == NULL || key == NULL) { + return NULL; + } + + lv_rb_node_t * node = lv_rb_insert(&lru->rb, key); + if(node == NULL) + goto FAILED_HANDLER2; + + void * data = node->data; + lv_cache_entry_t * entry = lv_cache_entry_get_entry(data, lru->cache.node_size); + lv_memcpy(data, key, lru->cache.node_size); + + void * lru_node = _lv_ll_ins_head(&lru->ll); + if(lru_node == NULL) + goto FAILED_HANDLER1; + + lv_memcpy(lru_node, &node, sizeof(void *)); + lv_memcpy(get_lru_node(lru, node), &lru_node, sizeof(void *)); + + lv_cache_entry_init(entry, &lru->cache, lru->cache.node_size); + goto FAILED_HANDLER2; + +FAILED_HANDLER1: + lv_rb_drop_node(&lru->rb, node); + node = NULL; +FAILED_HANDLER2: + return node; +} + +inline static void ** get_lru_node(lv_lru_rb_t_ * lru, lv_rb_node_t * node) +{ + return (void **)((char *)node->data + lru->rb.size - sizeof(void *)); +} + +static void * alloc_cb(void) +{ + void * res = lv_malloc(sizeof(lv_lru_rb_t_)); + LV_ASSERT_MALLOC(res); + if(res == NULL) { + LV_LOG_ERROR("malloc failed"); + return NULL; + } + + lv_memzero(res, sizeof(lv_lru_rb_t_)); + return res; +} + +static bool init_cnt_cb(lv_cache_t * cache) +{ + lv_lru_rb_t_ * lru = (lv_lru_rb_t_ *)cache; + + LV_ASSERT_NULL(lru->cache.ops.compare_cb); + LV_ASSERT_NULL(lru->cache.ops.free_cb); + LV_ASSERT(lru->cache.node_size > 0); + + if(lru->cache.node_size <= 0 || lru->cache.max_size <= 0 + || lru->cache.ops.compare_cb == NULL || lru->cache.ops.free_cb == NULL) { + return false; + } + + /*add void* to store the ll node pointer*/ + if(!lv_rb_init(&lru->rb, lru->cache.ops.compare_cb, lv_cache_entry_get_size(lru->cache.node_size) + sizeof(void *))) { + return NULL; + } + _lv_ll_init(&lru->ll, sizeof(void *)); + + lru->get_data_size_cb = cnt_get_data_size_cb; + + return lru; +} + +static bool init_size_cb(lv_cache_t * cache) +{ + lv_lru_rb_t_ * lru = (lv_lru_rb_t_ *)cache; + + LV_ASSERT_NULL(lru->cache.ops.compare_cb); + LV_ASSERT_NULL(lru->cache.ops.free_cb); + LV_ASSERT(lru->cache.node_size > 0); + + if(lru->cache.node_size <= 0 || lru->cache.max_size <= 0 + || lru->cache.ops.compare_cb == NULL || lru->cache.ops.free_cb == NULL) { + return false; + } + + /*add void* to store the ll node pointer*/ + if(!lv_rb_init(&lru->rb, lru->cache.ops.compare_cb, lv_cache_entry_get_size(lru->cache.node_size) + sizeof(void *))) { + return NULL; + } + _lv_ll_init(&lru->ll, sizeof(void *)); + + lru->get_data_size_cb = size_get_data_size_cb; + + return lru; +} + +static void destroy_cb(lv_cache_t * cache, void * user_data) +{ + LV_UNUSED(user_data); + + lv_lru_rb_t_ * lru = (lv_lru_rb_t_ *)cache; + + LV_ASSERT_NULL(lru); + + if(lru == NULL) { + return; + } + + cache->clz->drop_all_cb(cache, user_data); +} + +static lv_cache_entry_t * get_cb(lv_cache_t * cache, const void * key, void * user_data) +{ + LV_UNUSED(user_data); + + lv_lru_rb_t_ * lru = (lv_lru_rb_t_ *)cache; + + LV_ASSERT_NULL(lru); + LV_ASSERT_NULL(key); + + if(lru == NULL || key == NULL) { + return NULL; + } + + /*try the first ll node first*/ + void * head = _lv_ll_get_head(&lru->ll); + if(head) { + lv_rb_node_t * node = *(lv_rb_node_t **)head; + void * data = node->data; + lv_cache_entry_t * entry = lv_cache_entry_get_entry(data, cache->node_size); + if(lru->cache.ops.compare_cb(data, key) == 0) { + return entry; + } + } + + lv_rb_node_t * node = lv_rb_find(&lru->rb, key); + /*cache hit*/ + if(node) { + void * lru_node = *get_lru_node(lru, node); + head = _lv_ll_get_head(&lru->ll); + _lv_ll_move_before(&lru->ll, lru_node, head); + + lv_cache_entry_t * entry = lv_cache_entry_get_entry(node->data, cache->node_size); + return entry; + } + return NULL; +} + +static lv_cache_entry_t * add_cb(lv_cache_t * cache, const void * key, void * user_data) +{ + LV_UNUSED(user_data); + + lv_lru_rb_t_ * lru = (lv_lru_rb_t_ *)cache; + + LV_ASSERT_NULL(lru); + LV_ASSERT_NULL(key); + + if(lru == NULL || key == NULL) { + return NULL; + } + + uint32_t data_size = lru->get_data_size_cb(key); + if(data_size > lru->cache.max_size) { + LV_LOG_ERROR("data size (%" LV_PRIu32 ") is larger than max size (%" LV_PRIu32 ")", data_size, + (uint32_t)lru->cache.max_size); + return NULL; + } + + void * tail = _lv_ll_get_tail(&lru->ll); + void * curr = tail; + while(cache->size + data_size > lru->cache.max_size) { + if(curr == NULL) { + LV_LOG_ERROR("failed to drop cache"); + return NULL; + } + + lv_rb_node_t * tail_node = *(lv_rb_node_t **)curr; + void * search_key = tail_node->data; + lv_cache_entry_t * entry = lv_cache_entry_get_entry(search_key, cache->node_size); + if(lv_cache_entry_get_ref(entry) == 0) { + cache->clz->drop_cb(cache, search_key, user_data); + curr = _lv_ll_get_tail(&lru->ll); + continue; + } + + curr = _lv_ll_get_prev(&lru->ll, curr); + } + + /*cache miss*/ + lv_rb_node_t * new_node = alloc_new_node(lru, (void *)key, user_data); + if(new_node == NULL) { + return NULL; + } + + lv_cache_entry_t * entry = lv_cache_entry_get_entry(new_node->data, cache->node_size); + + cache->size += data_size; + + return entry; +} + +static void remove_cb(lv_cache_t * cache, lv_cache_entry_t * entry, void * user_data) +{ + LV_UNUSED(user_data); + + lv_lru_rb_t_ * lru = (lv_lru_rb_t_ *)cache; + + LV_ASSERT_NULL(lru); + LV_ASSERT_NULL(entry); + + if(lru == NULL || entry == NULL) { + return; + } + + void * data = lv_cache_entry_get_data(entry); + lv_rb_node_t * node = lv_rb_find(&lru->rb, data); + if(node == NULL) { + return; + } + + void * lru_node = *get_lru_node(lru, node); + lv_rb_remove_node(&lru->rb, node); + _lv_ll_remove(&lru->ll, lru_node); + lv_free(lru_node); + + cache->size -= lru->get_data_size_cb(data); +} + +static void drop_cb(lv_cache_t * cache, const void * key, void * user_data) +{ + lv_lru_rb_t_ * lru = (lv_lru_rb_t_ *)cache; + + LV_ASSERT_NULL(lru); + LV_ASSERT_NULL(key); + + if(lru == NULL || key == NULL) { + return; + } + + lv_rb_node_t * node = lv_rb_find(&lru->rb, key); + if(node == NULL) { + return; + } + + void * data = node->data; + + lru->cache.ops.free_cb(data, user_data); + cache->size -= lru->get_data_size_cb(data); + + lv_cache_entry_t * entry = lv_cache_entry_get_entry(data, cache->node_size); + void * lru_node = *get_lru_node(lru, node); + + lv_rb_remove_node(&lru->rb, node); + lv_cache_entry_delete(entry); + + _lv_ll_remove(&lru->ll, lru_node); + lv_free(lru_node); +} + +static void drop_all_cb(lv_cache_t * cache, void * user_data) +{ + lv_lru_rb_t_ * lru = (lv_lru_rb_t_ *)cache; + + LV_ASSERT_NULL(lru); + + if(lru == NULL) { + return; + } + + uint32_t used_cnt = 0; + lv_rb_node_t ** node; + _LV_LL_READ(&lru->ll, node) { + /*free user handled data and do other clean up*/ + void * search_key = (*node)->data; + lv_cache_entry_t * entry = lv_cache_entry_get_entry(search_key, cache->node_size); + if(lv_cache_entry_get_ref(entry) == 0) { + lru->cache.ops.free_cb(search_key, user_data); + } + else { + LV_LOG_WARN("entry (%p) is still referenced (%" LV_PRId32 ")", entry, lv_cache_entry_get_ref(entry)); + used_cnt++; + } + } + if(used_cnt > 0) { + LV_LOG_WARN("%" LV_PRId32 " entries are still referenced", used_cnt); + } + + lv_rb_destroy(&lru->rb); + _lv_ll_clear(&lru->ll); + + cache->size = 0; +} + +static uint32_t cnt_get_data_size_cb(const void * data) +{ + LV_UNUSED(data); + return 1; +} + +static uint32_t size_get_data_size_cb(const void * data) +{ + lv_cache_slot_size_t * slot = (lv_cache_slot_size_t *)data; + return slot->size; +} diff --git a/src/misc/cache/_lv_cache_lru_rb.h b/src/misc/cache/_lv_cache_lru_rb.h new file mode 100644 index 0000000000..a27110b94d --- /dev/null +++ b/src/misc/cache/_lv_cache_lru_rb.h @@ -0,0 +1,44 @@ +/** +* @file _lv_cache_lru_rb.h +* +*/ + +#ifndef LV_CACHE_LRU_RB_H +#define LV_CACHE_LRU_RB_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "lv_cache_entry.h" +#include "lv_cache_private.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/************************* + * GLOBAL VARIABLES + *************************/ +LV_ATTRIBUTE_EXTERN_DATA extern const lv_cache_class_t lv_cache_class_lru_rb_count; +LV_ATTRIBUTE_EXTERN_DATA extern const lv_cache_class_t lv_cache_class_lru_rb_size; +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_CACHE_LRU_RB_H*/ diff --git a/src/misc/cache/lv_cache.c b/src/misc/cache/lv_cache.c new file mode 100644 index 0000000000..846694848f --- /dev/null +++ b/src/misc/cache/lv_cache.c @@ -0,0 +1,213 @@ +/** +* @file lv_cache.c +* +*/ + +/********************* + * INCLUDES + *********************/ +#include "lv_cache.h" +#include "../../stdlib/lv_sprintf.h" +#include "../lv_assert.h" +#include "lv_cache_entry_private.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static void cache_drop_internal_no_lock(lv_cache_t * cache, const void * key, void * user_data); +/********************** + * GLOBAL VARIABLES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +lv_cache_t * lv_cache_create(const lv_cache_class_t * cache_class, + size_t node_size, size_t max_size, + lv_cache_ops_t ops) +{ + lv_cache_t * cache = cache_class->alloc_cb(); + LV_ASSERT_MALLOC(cache); + + cache->clz = cache_class; + cache->node_size = node_size; + cache->max_size = max_size; + cache->size = 0; + cache->ops = ops; + + cache->clz->init_cb(cache); + + lv_mutex_init(&cache->lock); + + return cache; +} + +void lv_cache_destroy(lv_cache_t * cache, void * user_data) +{ + LV_ASSERT_NULL(cache); + + lv_mutex_lock(&cache->lock); + cache->clz->destroy_cb(cache, user_data); + lv_mutex_unlock(&cache->lock); + lv_mutex_delete(&cache->lock); + lv_free(cache); +} + +lv_cache_entry_t * lv_cache_acquire(lv_cache_t * cache, const void * key, void * user_data) +{ + LV_ASSERT_NULL(cache); + LV_ASSERT_NULL(key); + + lv_mutex_lock(&cache->lock); + lv_cache_entry_t * entry = cache->clz->get_cb(cache, key, user_data); + if(entry != NULL) { + lv_cache_entry_acquire_data(entry); + } + lv_mutex_unlock(&cache->lock); + return entry; +} +void lv_cache_release(lv_cache_t * cache, lv_cache_entry_t * entry, void * user_data) +{ + LV_ASSERT_NULL(entry); + + lv_mutex_lock(&cache->lock); + lv_cache_entry_release_data(entry, user_data); + + if(lv_cache_entry_get_ref(entry) == 0 && lv_cache_entry_is_invalid(entry)) { + cache->ops.free_cb(lv_cache_entry_get_data(entry), user_data); + lv_cache_entry_delete(entry); + } + lv_mutex_unlock(&cache->lock); +} +lv_cache_entry_t * lv_cache_add(lv_cache_t * cache, const void * key, void * user_data) +{ + LV_ASSERT_NULL(cache); + LV_ASSERT_NULL(key); + + lv_mutex_lock(&cache->lock); + lv_cache_entry_t * entry = cache->clz->add_cb(cache, key, user_data); + if(entry != NULL) { + lv_cache_entry_acquire_data(entry); + } + lv_mutex_unlock(&cache->lock); + return entry; +} +lv_cache_entry_t * lv_cache_acquire_or_create(lv_cache_t * cache, const void * key, void * user_data) +{ + LV_ASSERT_NULL(cache); + LV_ASSERT_NULL(key); + + lv_mutex_lock(&cache->lock); + lv_cache_entry_t * entry = cache->clz->get_cb(cache, key, user_data); + if(entry != NULL) { + lv_cache_entry_acquire_data(entry); + lv_mutex_unlock(&cache->lock); + return entry; + } + entry = cache->clz->add_cb(cache, key, user_data); + if(entry == NULL) { + lv_mutex_unlock(&cache->lock); + return NULL; + } + bool create_res = cache->ops.create_cb(lv_cache_entry_get_data(entry), user_data); + if(create_res == false) { + cache->clz->remove_cb(cache, entry, user_data); + lv_cache_entry_delete(entry); + entry = NULL; + } + else { + lv_cache_entry_acquire_data(entry); + } + lv_mutex_unlock(&cache->lock); + return entry; +} +void lv_cache_drop(lv_cache_t * cache, const void * key, void * user_data) +{ + LV_ASSERT_NULL(cache); + LV_ASSERT_NULL(key); + + lv_mutex_lock(&cache->lock); + cache_drop_internal_no_lock(cache, key, user_data); + lv_mutex_unlock(&cache->lock); +} +void lv_cache_drop_all(lv_cache_t * cache, void * user_data) +{ + LV_ASSERT_NULL(cache); + + lv_mutex_lock(&cache->lock); + cache->clz->drop_all_cb(cache, user_data); + lv_mutex_unlock(&cache->lock); +} + +void lv_cache_set_max_size(lv_cache_t * cache, size_t max_size, void * user_data) +{ + LV_UNUSED(user_data); + cache->max_size = max_size; +} +size_t lv_cache_get_max_size(lv_cache_t * cache, void * user_data) +{ + LV_UNUSED(user_data); + return cache->max_size; +} +size_t lv_cache_get_size(lv_cache_t * cache, void * user_data) +{ + LV_UNUSED(user_data); + return cache->size; +} +size_t lv_cache_get_free_size(lv_cache_t * cache, void * user_data) +{ + LV_UNUSED(user_data); + return cache->max_size - cache->size; +} +void lv_cache_set_compare_cb(lv_cache_t * cache, lv_cache_compare_cb_t compare_cb, void * user_data) +{ + LV_UNUSED(user_data); + cache->ops.compare_cb = compare_cb; +} +void lv_cache_set_create_cb(lv_cache_t * cache, lv_cache_create_cb_t alloc_cb, void * user_data) +{ + LV_UNUSED(user_data); + cache->ops.create_cb = alloc_cb; +} +void lv_cache_set_free_cb(lv_cache_t * cache, lv_cache_free_cb_t free_cb, void * user_data) +{ + LV_UNUSED(user_data); + cache->ops.free_cb = free_cb; +} +/********************** + * STATIC FUNCTIONS + **********************/ +static void cache_drop_internal_no_lock(lv_cache_t * cache, const void * key, void * user_data) +{ + lv_cache_entry_t * entry = cache->clz->get_cb(cache, key, user_data); + if(entry == NULL) { + return; + } + + if(lv_cache_entry_get_ref(entry) == 0) { + cache->clz->remove_cb(cache, entry, user_data); + cache->ops.free_cb(lv_cache_entry_get_data(entry), user_data); + lv_cache_entry_delete(entry); + } + else { + lv_cache_entry_set_invalid(entry, true); + cache->clz->remove_cb(cache, entry, user_data); + } +} diff --git a/src/misc/cache/lv_cache.h b/src/misc/cache/lv_cache.h new file mode 100644 index 0000000000..c79a00e76b --- /dev/null +++ b/src/misc/cache/lv_cache.h @@ -0,0 +1,67 @@ +/** +* @file lv_cache.h +* +*/ + +#ifndef LV_CACHE1_H +#define LV_CACHE1_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "lv_cache_entry.h" +#include "lv_cache_private.h" +#include +#include + +#include "_lv_cache_lru_rb.h" + +#include "lv_image_cache.h" +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ +lv_cache_t * lv_cache_create(const lv_cache_class_t * cache_class, + size_t node_size, size_t max_size, + lv_cache_ops_t ops); +void lv_cache_destroy(lv_cache_t * cache, void * user_data); + +lv_cache_entry_t * lv_cache_acquire(lv_cache_t * cache, const void * key, void * user_data); +lv_cache_entry_t * lv_cache_acquire_or_create(lv_cache_t * cache, const void * key, void * user_data); +lv_cache_entry_t * lv_cache_add(lv_cache_t * cache, const void * key, void * user_data); +void lv_cache_release(lv_cache_t * cache, lv_cache_entry_t * entry, void * user_data); +void lv_cache_drop(lv_cache_t * cache, const void * key, void * user_data); +void lv_cache_drop_all(lv_cache_t * cache, void * user_data); + +void lv_cache_set_max_size(lv_cache_t * cache, size_t max_size, void * user_data); +size_t lv_cache_get_max_size(lv_cache_t * cache, void * user_data); +size_t lv_cache_get_size(lv_cache_t * cache, void * user_data); +size_t lv_cache_get_free_size(lv_cache_t * cache, void * user_data); + +void lv_cache_set_compare_cb(lv_cache_t * cache, lv_cache_compare_cb_t compare_cb, void * user_data); +void lv_cache_set_create_cb(lv_cache_t * cache, lv_cache_create_cb_t alloc_cb, void * user_data); +void lv_cache_set_free_cb(lv_cache_t * cache, lv_cache_free_cb_t free_cb, void * user_data); +/************************* + * GLOBAL VARIABLES + *************************/ + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_CACHE_H*/ diff --git a/src/misc/cache/lv_cache_entry.c b/src/misc/cache/lv_cache_entry.c new file mode 100644 index 0000000000..242e1a0f26 --- /dev/null +++ b/src/misc/cache/lv_cache_entry.c @@ -0,0 +1,167 @@ +/** +* @file lv_cache_entry.c +* + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_cache_entry.h" +#include "../../stdlib/lv_sprintf.h" +#include "../lv_assert.h" +#include "lv_cache.h" +#include "lv_cache_entry_private.h" +#include "lv_cache_private.h" +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +struct _lv_cache_entry_t { + const lv_cache_t * cache; + int32_t ref_cnt; + uint32_t node_size; + + bool is_invalid; +}; +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * GLOBAL VARIABLES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +void lv_cache_entry_reset_ref(lv_cache_entry_t * entry) +{ + LV_ASSERT_NULL(entry); + entry->ref_cnt = 0; +} +void lv_cache_entry_inc_ref(lv_cache_entry_t * entry) +{ + LV_ASSERT_NULL(entry); + entry->ref_cnt++; +} +void lv_cache_entry_dec_ref(lv_cache_entry_t * entry) +{ + LV_ASSERT_NULL(entry); + entry->ref_cnt--; + if(entry->ref_cnt < 0) { + LV_LOG_WARN("ref_cnt(%" LV_PRIu32 ") < 0", entry->ref_cnt); + entry->ref_cnt = 0; + } +} +int32_t lv_cache_entry_get_ref(lv_cache_entry_t * entry) +{ + LV_ASSERT_NULL(entry); + return entry->ref_cnt; +} +uint32_t lv_cache_entry_get_node_size(lv_cache_entry_t * entry) +{ + return entry->node_size; +} +void lv_cache_entry_set_node_size(lv_cache_entry_t * entry, uint32_t node_size) +{ + LV_ASSERT_NULL(entry); + entry->node_size = node_size; +} +void lv_cache_entry_set_invalid(lv_cache_entry_t * entry, bool is_invalid) +{ + LV_ASSERT_NULL(entry); + entry->is_invalid = is_invalid; +} +bool lv_cache_entry_is_invalid(lv_cache_entry_t * entry) +{ + LV_ASSERT_NULL(entry); + return entry->is_invalid; +} +void * lv_cache_entry_get_data(lv_cache_entry_t * entry) +{ + LV_ASSERT_NULL(entry); + return (uint8_t *)entry - entry->node_size; +} +void * lv_cache_entry_acquire_data(lv_cache_entry_t * entry) +{ + LV_ASSERT_NULL(entry); + + lv_cache_entry_inc_ref(entry); + return lv_cache_entry_get_data(entry); +} +void lv_cache_entry_release_data(lv_cache_entry_t * entry, void * user_data) +{ + LV_UNUSED(user_data); + + LV_ASSERT_NULL(entry); + if(lv_cache_entry_get_ref(entry) == 0) { + LV_LOG_ERROR("ref_cnt(%" LV_PRIu32 ") == 0", entry->ref_cnt); + return; + } + + lv_cache_entry_dec_ref(entry); +} +lv_cache_entry_t * lv_cache_entry_get_entry(void * data, const uint32_t node_size) +{ + LV_ASSERT_NULL(data); + return (lv_cache_entry_t *)((uint8_t *)data + node_size); +} +void lv_cache_entry_set_cache(lv_cache_entry_t * entry, const lv_cache_t * cache) +{ + LV_ASSERT_NULL(entry); + entry->cache = cache; +} +const lv_cache_t * lv_cache_entry_get_cache(const lv_cache_entry_t * entry) +{ + LV_ASSERT_NULL(entry); + return entry->cache; +} + +uint32_t lv_cache_entry_get_size(const uint32_t node_size) +{ + return node_size + sizeof(lv_cache_entry_t); +} +lv_cache_entry_t * lv_cache_entry_alloc(const uint32_t node_size, const lv_cache_t * cache) +{ + void * res = lv_malloc_zeroed(lv_cache_entry_get_size(node_size)); + LV_ASSERT_MALLOC(res) + if(res == NULL) { + LV_LOG_ERROR("malloc failed"); + return NULL; + } + lv_cache_entry_t * entry = (lv_cache_entry_t *)res; + lv_cache_entry_init(entry, cache, node_size); + return (lv_cache_entry_t *)((uint8_t *)entry + node_size); +} +void lv_cache_entry_init(lv_cache_entry_t * entry, const lv_cache_t * cache, const uint32_t node_size) +{ + LV_ASSERT_NULL(entry); + LV_ASSERT_NULL(cache); + + entry->cache = cache; + entry->node_size = node_size; + entry->ref_cnt = 0; + entry->is_invalid = false; +} +void lv_cache_entry_delete(lv_cache_entry_t * entry) +{ + LV_ASSERT_NULL(entry); + + void * data = lv_cache_entry_get_data(entry); + lv_free(data); +} +/********************** + * STATIC FUNCTIONS + **********************/ diff --git a/src/misc/cache/lv_cache_entry.h b/src/misc/cache/lv_cache_entry.h new file mode 100644 index 0000000000..c2f8585eae --- /dev/null +++ b/src/misc/cache/lv_cache_entry.h @@ -0,0 +1,55 @@ +/** +* @file lv_cache_entry.h +* + */ + +#ifndef LV_CACHE_ENTRY_H +#define LV_CACHE_ENTRY_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "../../osal/lv_os.h" +#include "../lv_types.h" +#include "lv_cache_private.h" +#include +#include +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ +uint32_t lv_cache_entry_get_size(const uint32_t node_size); +int32_t lv_cache_entry_get_ref(lv_cache_entry_t * entry); +uint32_t lv_cache_entry_get_node_size(lv_cache_entry_t * entry); +bool lv_cache_entry_is_invalid(lv_cache_entry_t * entry); +void * lv_cache_entry_get_data(lv_cache_entry_t * entry); +const lv_cache_t * lv_cache_entry_get_cache(const lv_cache_entry_t * entry); +lv_cache_entry_t * lv_cache_entry_get_entry(void * data, const uint32_t node_size); + +lv_cache_entry_t * lv_cache_entry_alloc(const uint32_t node_size, const lv_cache_t * cache); +void lv_cache_entry_init(lv_cache_entry_t * entry, const lv_cache_t * cache, const uint32_t node_size); +void lv_cache_entry_delete(lv_cache_entry_t * entry); +/************************* + * GLOBAL VARIABLES + *************************/ + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_CACHE_ENTRY_H*/ diff --git a/src/misc/cache/lv_cache_entry_private.h b/src/misc/cache/lv_cache_entry_private.h new file mode 100644 index 0000000000..227585e1ea --- /dev/null +++ b/src/misc/cache/lv_cache_entry_private.h @@ -0,0 +1,51 @@ +/** +* @file lv_cache_entry_private.h +* + */ + +#ifndef LV_CACHE_ENTRY_PRIVATE +#define LV_CACHE_ENTRY_PRIVATE + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "../lv_types.h" +#include +#include +#include "../../osal/lv_os.h" +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ +void lv_cache_entry_reset_ref(lv_cache_entry_t * entry); +void lv_cache_entry_inc_ref(lv_cache_entry_t * entry); +void lv_cache_entry_dec_ref(lv_cache_entry_t * entry); +void lv_cache_entry_set_node_size(lv_cache_entry_t * entry, uint32_t node_size); +void lv_cache_entry_set_invalid(lv_cache_entry_t * entry, bool is_invalid); +void lv_cache_entry_set_cache(lv_cache_entry_t * entry, const lv_cache_t * cache); +void * lv_cache_entry_acquire_data(lv_cache_entry_t * entry); +void lv_cache_entry_release_data(lv_cache_entry_t * entry, void * user_data); +/************************* + * GLOBAL VARIABLES + *************************/ + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_CACHE_ENTRY_PRIVATE*/ diff --git a/src/misc/cache/lv_cache_private.h b/src/misc/cache/lv_cache_private.h new file mode 100644 index 0000000000..7a83e04d0c --- /dev/null +++ b/src/misc/cache/lv_cache_private.h @@ -0,0 +1,114 @@ +/** +* @file lv_cache_private.h +* +*/ + +#ifndef LV_CACHE_PRIVATE_H +#define LV_CACHE_PRIVATE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "../lv_types.h" +#include +#include +#include "../../osal/lv_os.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/*----------------- + * Cache entry slot + *----------------*/ +struct _lv_cache_ops_t; +struct _lv_cache_t; +struct _lv_cache_class_t; +struct _lv_cache_entry_t; + +typedef struct _lv_cache_ops_t lv_cache_ops_t; +typedef struct _lv_cache_t lv_cache_t; +typedef struct _lv_cache_class_t lv_cache_class_t; +typedef struct _lv_cache_entry_t lv_cache_entry_t; + +typedef int8_t lv_cache_compare_res_t; +typedef bool (*lv_cache_create_cb_t)(void * node, void * user_data); +typedef void (*lv_cache_free_cb_t)(void * node, void * user_data); +typedef lv_cache_compare_res_t (*lv_cache_compare_cb_t)(const void * a, const void * b); + +typedef void * (*lv_cache_alloc_cb_t)(void); +typedef bool (*lv_cache_init_cb_t)(lv_cache_t * cache); +typedef void (*lv_cache_destroy_cb_t)(lv_cache_t * cache, void * user_data); +typedef lv_cache_entry_t * (*lv_cache_get_cb_t)(lv_cache_t * cache, const void * key, void * user_data); +typedef lv_cache_entry_t * (*lv_cache_add_cb_t)(lv_cache_t * cache, const void * key, void * user_data); +typedef void (*lv_cache_remove_cb_t)(lv_cache_t * cache, lv_cache_entry_t * entry, void * user_data); +typedef void (*lv_cache_drop_cb_t)(lv_cache_t * cache, const void * key, void * user_data); +typedef void (*lv_cache_clear_cb_t)(lv_cache_t * cache, void * user_data); + +struct _lv_cache_ops_t { + lv_cache_compare_cb_t compare_cb; + lv_cache_create_cb_t create_cb; + lv_cache_free_cb_t free_cb; +}; + +struct _lv_cache_t { + const lv_cache_class_t * clz; + + size_t node_size; + + size_t max_size; + size_t size; + + lv_cache_ops_t ops; + + lv_mutex_t lock; +}; + +struct _lv_cache_class_t { + lv_cache_alloc_cb_t alloc_cb; + lv_cache_init_cb_t init_cb; + lv_cache_destroy_cb_t destroy_cb; + + lv_cache_get_cb_t get_cb; + lv_cache_add_cb_t add_cb; + lv_cache_remove_cb_t remove_cb; + lv_cache_drop_cb_t drop_cb; + lv_cache_clear_cb_t drop_all_cb; +}; + +/*----------------- + * Cache entry slot + *----------------*/ + +struct _lv_cache_slot_size_t; + +typedef struct _lv_cache_slot_size_t lv_cache_slot_size_t; + +struct _lv_cache_slot_size_t { + size_t size; +}; +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/************************* + * GLOBAL VARIABLES + *************************/ + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_CACHE_PRIVATE_H*/ diff --git a/src/misc/cache/lv_image_cache.c b/src/misc/cache/lv_image_cache.c new file mode 100644 index 0000000000..728224669d --- /dev/null +++ b/src/misc/cache/lv_image_cache.c @@ -0,0 +1,59 @@ +/** +* @file lv_image_cache.c +* + */ + +/********************* + * INCLUDES + *********************/ +#include "../lv_assert.h" +#include "lv_image_cache.h" +#include "../../core/lv_global.h" +/********************* + * DEFINES + *********************/ +#define img_cache_p (LV_GLOBAL_DEFAULT()->img_cache) +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * GLOBAL VARIABLES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ +void lv_image_cache_drop(const void * src) +{ +#if LV_CACHE_DEF_SIZE > 0 + if(src == NULL) { + lv_cache_drop_all(img_cache_p, NULL); + return; + } + + lv_image_cache_data_t search_key = { + .src = src, + .src_type = lv_image_src_get_type(src), + }; + + lv_cache_drop(img_cache_p, &search_key, NULL); +#else + LV_UNUSED(src); +#endif +} +/********************** + * STATIC FUNCTIONS + **********************/ diff --git a/src/misc/lv_cache_builtin.h b/src/misc/cache/lv_image_cache.h similarity index 58% rename from src/misc/lv_cache_builtin.h rename to src/misc/cache/lv_image_cache.h index 846a9029df..3b23b3dfbe 100644 --- a/src/misc/lv_cache_builtin.h +++ b/src/misc/cache/lv_image_cache.h @@ -1,10 +1,10 @@ /** - * @file lv_cache_builtin.h - * +* @file lv_image_cache.h +* */ -#ifndef LV_CACHE_BUILTIN_H -#define LV_CACHE_BUILTIN_H +#ifndef LV_IMAGE_CACHE_H +#define LV_IMAGE_CACHE_H #ifdef __cplusplus extern "C" { @@ -13,7 +13,7 @@ extern "C" { /********************* * INCLUDES *********************/ -#include "lv_ll.h" +#include "lv_cache_private.h" /********************* * DEFINES @@ -23,18 +23,13 @@ extern "C" { * 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); - -void _lv_cache_builtin_deinit(void); +void lv_image_cache_drop(const void * src); +/************************* + * GLOBAL VARIABLES + *************************/ /********************** * MACROS @@ -44,4 +39,4 @@ void _lv_cache_builtin_deinit(void); } /*extern "C"*/ #endif -#endif /*LV_CACHE_BUILTIN_H*/ +#endif /*LV_IMAGE_CACHE_H*/ diff --git a/src/misc/lv_cache.c b/src/misc/lv_cache.c deleted file mode 100644 index 8180d6f258..0000000000 --- a/src/misc/lv_cache.c +++ /dev/null @@ -1,164 +0,0 @@ -/** - * @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); -} - -void _lv_cache_deinit(void) -{ - lv_mutex_delete(&_cache_manager.mutex); -} - -void lv_cache_set_manager(lv_cache_manager_t * manager) -{ - LV_ASSERT(_cache_manager.locked); - if(manager == NULL) return; - - if(_cache_manager.empty_cb != NULL) _cache_manager.empty_cb(); - else if(_cache_manager.set_max_size_cb != NULL) _cache_manager.set_max_size_cb(0); - - _cache_manager.add_cb = manager->add_cb; - _cache_manager.find_by_data_cb = manager->find_by_data_cb; - _cache_manager.invalidate_cb = manager->invalidate_cb; - _cache_manager.get_data_cb = manager->get_data_cb; - _cache_manager.release_cb = manager->release_cb; - _cache_manager.set_max_size_cb = manager->set_max_size_cb; - _cache_manager.empty_cb = manager->empty_cb; - - if(_cache_manager.set_max_size_cb != NULL) _cache_manager.set_max_size_cb(_cache_manager.max_size); -} - -lv_cache_entry_t * lv_cache_add(const void * data, size_t data_size, uint32_t data_type, size_t memory_usage) -{ - LV_ASSERT(_cache_manager.locked); - if(_cache_manager.add_cb == NULL) return NULL; - - return _cache_manager.add_cb(data, data_size, data_type, memory_usage); -} - -lv_cache_entry_t * lv_cache_find_by_data(const void * data, size_t data_size, uint32_t data_type) -{ - LV_ASSERT(_cache_manager.locked); - if(_cache_manager.find_by_data_cb == NULL) return NULL; - - return _cache_manager.find_by_data_cb(data, data_size, data_type); -} - -lv_cache_entry_t * lv_cache_find_by_src(lv_cache_entry_t * entry, const void * src, lv_cache_src_type_t src_type) -{ - LV_ASSERT(_cache_manager.locked); - if(_cache_manager.find_by_src_cb == NULL) return NULL; - - return _cache_manager.find_by_src_cb(entry, src, src_type); -} - -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); -} - -void lv_cache_invalidate_by_src(const void * src, lv_cache_src_type_t src_type) -{ - lv_cache_entry_t * next; - LV_ASSERT(_cache_manager.locked); - lv_cache_entry_t * entry = lv_cache_find_by_src(NULL, src, src_type); - while(entry) { - next = lv_cache_find_by_src(entry, src, src_type); - lv_cache_invalidate(entry); - entry = next; - } -} - -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); -} - -uint32_t lv_cache_register_data_type(void) -{ - _cache_manager.last_data_type++; - return _cache_manager.last_data_type; -} - -/********************** - * STATIC FUNCTIONS - **********************/ diff --git a/src/misc/lv_cache.h b/src/misc/lv_cache.h deleted file mode 100644 index f22bc6875b..0000000000 --- a/src/misc/lv_cache.h +++ /dev/null @@ -1,306 +0,0 @@ -/** - * @file lv_cache.h - * - */ - -#ifndef LV_CACHE_H -#define LV_CACHE_H - -#ifdef __cplusplus -extern "C" { -#endif - -/********************* - * INCLUDES - *********************/ -#include -#include -#include -#include "../osal/lv_os.h" - -/********************* - * DEFINES - *********************/ -#define LV_CACHE_DATA_TYPE_NOT_SET 0xFFFFFFFF - -/********************** - * TYPEDEFS - **********************/ - -typedef enum { - LV_CACHE_SRC_TYPE_PATH, - LV_CACHE_SRC_TYPE_POINTER, -} lv_cache_src_type_t; - -typedef struct _lv_cache_entry_t { - - /** - * The data to cache. - * Can be just a pointer to a byte array, or pointer to a complex structure, or anything else*/ - const void * data; - - /** - * Size of data in bytes. - * It's not the size of the cached data, just the size of the structure pointed by `data` - * E.g. `data` can point to descriptor struct and the size of that struct needs to be stored here. - * It can be used in the `compary_cb` to compare `data` fields of the entries with a requested one*/ - uint32_t data_size; - - /**An integer ID to tell the type of the cached data. - * If set to `LV_CACHE_DATA_TYPE_NOT_SET` `lv_cache_find_by_data` cannot be used*/ - uint32_t data_type; - - /** - * The source from which the cache is created. - * It's can or cannot be the same as data, or different, or NULL. - * It's used to find the cache entries which are relted to same source. - * E.g. the same image, font, etc. */ - const void * src; - - lv_cache_src_type_t src_type; - - /**Arbitrary parameters to better identify the source*/ - int32_t param1; - int32_t param2; - - /** Memory in bytes used by data. */ - uint32_t memory_usage; - - /** - * Called to compare the data of cache entries. - * Before calling this function LVGL checks that `data_size` of both entries are the same. - * This callback look into `data` and check all the pointers and their content on any level. - * @param data1 first data to compare - * @param data2 second data to compare - * @param data_size size of data - * @return true: `data1` and `data2` are the same - */ - bool (*compare_cb)(const void * data1, const void * data2, size_t data_size); - - /** - * Called when the entry is invalidated to free its data - * @param e the cache entry to free - */ - void (*invalidate_cb)(struct _lv_cache_entry_t * e); - - /** User processing tag*/ - uint32_t process_state; - - /** 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; - - /** 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 data data the cache, can be a complex structure too - * @param data_size the size of data (if it's a struct then the size of the struct) - * @param data_type type of data to identify the kind of this cache entry - * @param memory_usage the size of memory used by this entry (`data` might contain pointers so it's size of all buffers related to entry) - * @return a handler for the new cache entry - */ -typedef lv_cache_entry_t * (*lv_cache_add_cb)(const void * data, size_t data_size, uint32_t data_type, - size_t memory_usage); - -/** - * Find a cache entry based on its data - * @param data the data to find - * @param data_size size of data - * @param data_type ID for the data type - * @return the cache entry with given `data` or NULL if not found - */ -typedef lv_cache_entry_t * (*lv_cache_find_by_data_cb)(const void * data, size_t data_size, uint32_t data_type); - -/** - * Get the next entry which has the given source and parameters - * @param prev_entry pointer to the previous entry from which the nest should be found. NULL means to start from the beginning. - * @param src a pointer or a string - * @param src_type element of lv_cache_src_type_t - * @return the cache entry with given source or NULL if not found - */ -typedef lv_cache_entry_t * (*lv_cache_find_by_src_cb)(lv_cache_entry_t * entry, const void * src, - lv_cache_src_type_t src_type); - -/** - * 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); - -/** - * Empty the cache. - */ -typedef void (*lv_cache_empty_cb)(void); - -typedef struct { - lv_cache_add_cb add_cb; - lv_cache_find_by_data_cb find_by_data_cb; - lv_cache_find_by_src_cb find_by_src_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_cache_empty_cb empty_cb; - - lv_mutex_t mutex; - size_t max_size; - uint32_t locked : 1; /**< Show the mutex state, used to log unlocked cache access*/ - uint32_t last_data_type; -} lv_cache_manager_t; - -/********************** - * GLOBAL PROTOTYPES - **********************/ - -/** - * Initialize the cache module - */ -void _lv_cache_init(void); - -/** - * Deinitialize the cache module - */ -void _lv_cache_deinit(void); - -/** - * Set new cache manager - * @param manager the new cache manager with callback functions set - */ -void lv_cache_set_manager(lv_cache_manager_t * manager); - -/** - * 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 data data the cache, can be a complex structure too - * @param data_size the size of data (if it's a struct then the size of the struct) - * @param data_type type of data to identify the kind of this cache entry - * @param memory_usage the size of memory used by this entry (`data` might contain pointers so it's size of all buffers related to entry) - * @return a handler for the new cache entry - */ -lv_cache_entry_t * lv_cache_add(const void * data, size_t data_size, uint32_t data_type, size_t memory_usage); - -/** - * Find a cache entry based on its data - * @param data the data to find - * @param data_size size of data - * @param data_type ID of data type - * @return the cache entry with given `data` or NULL if not found - */ -lv_cache_entry_t * lv_cache_find_by_data(const void * data, size_t data_size, uint32_t data_type); - -/** - * Get the next entry which has the given source and parameters - * @param prev_entry pointer to the previous entry from which the nest should be found. NULL means to start from the beginning. - * @param src a pointer or a string - * @param src_type element of lv_cache_src_type_t - * @return the cache entry with given source or NULL if not found - */ -lv_cache_entry_t * lv_cache_find_by_src(lv_cache_entry_t * entry, const void * src, lv_cache_src_type_t src_type); - -/** - * Invalidate (drop) a cache entry. It will call the entry's `invalidate_cb` to free the resources - * @param entry the entry to invalidate. (can be retrieved by `lv_cache_find()`) - */ -void lv_cache_invalidate(lv_cache_entry_t * entry); - -/** - * Invalidate all cache entries with a given source - * @param src a pointer or a string - * @param src_type element of lv_cache_src_type_t - */ -void lv_cache_invalidate_by_src(const void * src, lv_cache_src_type_t src_type); - -/** - * 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); - -/** - * Register a data type which can be used as `entry->data_type`. - * @return the registered unique data type ID. - */ -uint32_t lv_cache_register_data_type(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 deleted file mode 100644 index 8ca5cf9174..0000000000 --- a/src/misc/lv_cache_builtin.c +++ /dev/null @@ -1,238 +0,0 @@ -/** - * @file lv_cache_builtin.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(const void * data, size_t data_size, uint32_t data_type, size_t memory_usage); -static lv_cache_entry_t * find_by_data_cb(const void * data, size_t data_size, uint32_t data_type); -static lv_cache_entry_t * find_by_src_cb(lv_cache_entry_t * entry, const void * src, lv_cache_src_type_t src_type); -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 void empty_cb(void); -static bool drop_youngest(void); - -/********************** - * STATIC VARIABLES - **********************/ - -/********************** - * MACROS - **********************/ -#if LV_USE_LOG && LV_LOG_TRACE_CACHE - #define LV_TRACE_CACHE(...) LV_LOG_TRACE(__VA_ARGS__) -#else - #define LV_TRACE_CACHE(...) -#endif - -/********************** - * GLOBAL FUNCTIONS - **********************/ - -void _lv_cache_builtin_init(void) -{ - lv_memzero(&dsc, sizeof(lv_cache_builtin_dsc_t)); - _lv_ll_init(&dsc.entry_ll, sizeof(lv_cache_entry_t)); - - _cache_manager.add_cb = add_cb; - _cache_manager.find_by_data_cb = find_by_data_cb; - _cache_manager.find_by_src_cb = find_by_src_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; - _cache_manager.empty_cb = empty_cb; -} - -void _lv_cache_builtin_deinit(void) -{ - lv_cache_entry_t * entry = _lv_ll_get_head(&dsc.entry_ll); - lv_cache_entry_t * next; - while(entry) { - next = _lv_ll_get_next(&dsc.entry_ll, entry); - invalidate_cb(entry); - entry = next; - } - - _lv_ll_clear(&dsc.entry_ll); -} - -/********************** - * STATIC FUNCTIONS - **********************/ - -static lv_cache_entry_t * add_cb(const void * data, size_t data_size, uint32_t data_type, size_t memory_usage) -{ - size_t max_size = lv_cache_get_max_size(); - /*Can't cache data larger than max size*/ - - bool temporary = memory_usage > max_size ? true : false; - if(!temporary) { - /*Keep dropping items until there is enough space*/ - while(dsc.cur_size + memory_usage > _cache_manager.max_size) { - bool ret = drop_youngest(); - - /*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 * entry = _lv_ll_ins_head(&dsc.entry_ll); - lv_memzero(entry, sizeof(lv_cache_entry_t)); - entry->memory_usage = memory_usage; - entry->weight = 1; - entry->temporary = temporary; - entry->data = data; - entry->data_size = data_size; - entry->data_type = data_type; - - if(temporary) { - LV_TRACE_CACHE("Add temporary cache: %lu bytes", (unsigned long)memory_usage); - } - else { - LV_TRACE_CACHE("Add cache: %lu bytes", (unsigned long)memory_usage); - dsc.cur_size += memory_usage; - } - - return entry; -} - -static lv_cache_entry_t * find_by_data_cb(const void * data, size_t data_size, uint32_t data_type) -{ - lv_cache_entry_t * entry = _lv_ll_get_head(&dsc.entry_ll); - while(entry) { - if(entry->data_type == data_type && entry->data_size == data_size) { - if(entry->compare_cb(entry->data, data, data_size)) { - return entry; - } - } - - entry = _lv_ll_get_next(&dsc.entry_ll, entry); - } - - return NULL; -} - -static lv_cache_entry_t * find_by_src_cb(lv_cache_entry_t * entry, const void * src, lv_cache_src_type_t src_type) -{ - if(entry == NULL) entry = _lv_ll_get_head(&dsc.entry_ll); - else entry = _lv_ll_get_next(&dsc.entry_ll, entry); - - while(entry) { - if(src_type == LV_CACHE_SRC_TYPE_POINTER && entry->src == src) return entry; - if(src_type == LV_CACHE_SRC_TYPE_PATH && lv_strcmp(entry->src, src) == 0) return entry; - entry = _lv_ll_get_next(&dsc.entry_ll, entry); - } - - return NULL; -} - -static void invalidate_cb(lv_cache_entry_t * entry) -{ - if(entry == NULL) return; - - dsc.cur_size -= entry->memory_usage; - LV_TRACE_CACHE("Drop cache: %u bytes", (uint32_t)entry->memory_usage); - - if(entry->invalidate_cb) entry->invalidate_cb(entry); - - _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_youngest(); - - /*No item could be dropped. - *It can happen because the usage_count of the remaining items are not zero.*/ - if(ret == false) return; - } -} - -static void empty_cb(void) -{ - lv_cache_entry_t * entry_to_drop = NULL; - lv_cache_entry_t * entry = _lv_ll_get_head(&dsc.entry_ll); - while(entry) { - entry_to_drop = entry; - entry = _lv_ll_get_next(&dsc.entry_ll, entry); - invalidate_cb(entry_to_drop); - } -} - -static bool drop_youngest(void) -{ - int32_t life_min = INT32_MAX; - lv_cache_entry_t * entry_to_drop = NULL; - - lv_cache_entry_t * entry = _lv_ll_get_head(&dsc.entry_ll); - while(entry) { - if(entry->life < life_min && entry->usage_count == 0) entry_to_drop = entry; - entry = _lv_ll_get_next(&dsc.entry_ll, entry); - } - - if(entry_to_drop == NULL) { - return false; - } - - invalidate_cb(entry_to_drop); - return true; -} diff --git a/src/misc/lv_lru_rb.c b/src/misc/lv_lru_rb.c deleted file mode 100755 index 8e3ac61439..0000000000 --- a/src/misc/lv_lru_rb.c +++ /dev/null @@ -1,314 +0,0 @@ -/** - * @file lv_lru_rb.c - * - */ - -/** - * @brief cache model - * */ - -/*************************************************************************\ -* * -* ┏ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ┓ * -* ┏ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ┌ ─ ─ ─ ┐ * -* ┌ ─ ─ ─ ─ ─ ─ ─ ┃ ┃ Cache insert ┃ * -* ┃ RB Tree │ │Hitting│ head * -* └ ─ ─ ─ ─ ─ ─ ─ ┃ ┃ ─ ─ ─ ─ ┃ * -* ┃ ┌─┬─┬─┬─┐ ┌─────┐ * -* ┌──│◄│B│►│ │─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─┃─ ─ ╋ ─ ─▶│ B │ ┃ * -* ┃ │ └─┴─┴─┴─┘ └──▲──┘ * -* │ │ ┃ ┃ │ ┃ * -* ┃ │ │ ┌──┴──┐ * -* │ └──────┐ ┌ ─┃─ ─ ╋ ─ ─▶│ E │ ┃ * -* ┃ ▼ ┌ ─ ─│─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐ └──▲──┘ * -* ┌─┬─┬─┬─┐ ▼ │ ┃ ┃ │ ┃ * -* ┃│◄│A│►│ │─ ─ ┘ ┌─┬─┬─┬─┐ │ ┌──┴──┐ * -* └─┴─┴─┴─┘ ┌───│◄│D│►│ │─ ─ ─ ─ ─ ─│─ ╋ ┐ ┃ ─ ▶│ A │ ┌ ─ ─ ─ ─ ┐ ┃ * -* ┃ │ └─┴─┴─┴─┘ └──▲──┘ LRU * -* │ │ │ ┃ │ ┃ │ │ Cache │ ┃ * -* ┃ ▼ └──────┐ ┌──┴──┐ ─ ─ ─ ─ ─ * -* ┌─┬─┬─┬─┐ ▼ │ ┃ └ ─┃─ ─ ▶│ D │ ┃ * -* ┃ │◄│C│►│ │─ ─ ┌─┬─┬─┬─┐ └──▲──┘ * -* └─┴─┴─┴─┘ │ │◄│E│►│ │─ ┘ ┃ ┃ │ ┃ * -* ┃ └─┴─┴─┴─┘ ┌──┴──┐ * -* │ │ ─ ╋ ─ ─┃─ ─ ▶│ C │ ┃ * -* ┃ ─ ─ ─ ─ ┼ ─ ─ ┘ └──▲──┘ * -* ▼ ┃ ┃ ┌ ─ ─│─ ─ ┐ ┃ * -* ┃ ┌─┬─┬─┬─┐ ┌──┴──┐ * -* │◄│F│►│ │─ ─┃─ ─ ╋ ─ ┼▶│ F │ │ ┃ * -* ┃ └─┴─┴─┴─┘ └─────┘ * -* ┃ ┃ └ ─ ─ ─ ─ ┘ ┃ * -* ┃ remove * -* ┃ ┃ tail ┃ * -* ┗ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ * -* * -\*************************************************************************/ - -/********************* - * INCLUDES - *********************/ -#include "lv_lru_rb.h" -#include "lv_ll.h" -#include "lv_rb.h" -#include "../stdlib/lv_string.h" - -/********************* - * DEFINES - *********************/ - -/********************** - * TYPEDEFS - **********************/ -struct _lv_lru_rb_t { - lv_rb_t rb; - lv_ll_t lru_ll; - - size_t max_size; - size_t size; - lv_lru_rb_create_cb_t create_cb; - lv_lru_rb_free_cb_t free_cb; -}; -/********************** - * STATIC PROTOTYPES - **********************/ -static void * alloc_new_node(lv_lru_rb_t * lru, void * key, void * user_data); -inline static void ** get_lru_node(lv_lru_rb_t * lru, lv_rb_node_t * node); -/********************** - * GLOBAL VARIABLES - **********************/ - -/********************** - * STATIC VARIABLES - **********************/ - -/********************** - * MACROS - **********************/ - -/********************** - * GLOBAL FUNCTIONS - **********************/ - -lv_lru_rb_t * lv_lru_rb_create(size_t node_size, size_t max_size, lv_lru_rb_compare_cb_t compare_cb, - lv_lru_rb_create_cb_t create_cb, lv_lru_rb_free_cb_t free_cb) -{ - LV_ASSERT_NULL(compare_cb); - LV_ASSERT_NULL(create_cb); - LV_ASSERT_NULL(free_cb); - LV_ASSERT(node_size > 0); - LV_ASSERT(max_size > 0); - - if(node_size == 0 || max_size == 0 || compare_cb == NULL || create_cb == NULL || free_cb == NULL) { - return NULL; - } - - lv_lru_rb_t * lru; - lru = lv_malloc(sizeof(lv_lru_rb_t)); - LV_ASSERT_MALLOC(lru); - if(lru == NULL) { - return NULL; - } - - lv_memzero(lru, sizeof(lv_lru_rb_t)); - - /*add void* to store the ll node pointer*/ - if(!lv_rb_init(&lru->rb, (lv_rb_compare_t)compare_cb, node_size + sizeof(void *))) { - return NULL; - } - _lv_ll_init(&lru->lru_ll, sizeof(void *)); - - lv_lru_rb_set_max_size(lru, max_size, NULL); - lv_lru_rb_set_compare_cb(lru, compare_cb, NULL); - lv_lru_rb_set_create_cb(lru, create_cb, NULL); - lv_lru_rb_set_free_cb(lru, free_cb, NULL); - - return lru; -} - -void lv_lru_rb_destroy(lv_lru_rb_t * lru, void * user_data) -{ - LV_ASSERT_NULL(lru); - - if(lru == NULL) { - return; - } - - lv_lru_rb_drop_all(lru, user_data); - - lv_free(lru); -} - -void * lv_lru_rb_get_or_create(lv_lru_rb_t * lru, const void * key, void * user_data) -{ - LV_ASSERT_NULL(lru); - LV_ASSERT_NULL(key); - - if(lru == NULL || key == NULL) { - return NULL; - } - - /*try the first ll node first*/ - void * head = _lv_ll_get_head(&lru->lru_ll); - if(head) { - lv_rb_node_t * node = *(lv_rb_node_t **)head; - if(lru->rb.compare(node->data, key) == 0) { - return node->data; - } - } - - lv_rb_node_t * node = lv_rb_find(&lru->rb, key); - /*cache hit*/ - if(node) { - void * lru_node = *get_lru_node(lru, node); - head = _lv_ll_get_head(&lru->lru_ll); - _lv_ll_move_before(&lru->lru_ll, lru_node, head); - return node->data; - } - - while(lru->size >= lru->max_size) { - void * tail = _lv_ll_get_tail(&lru->lru_ll); - lv_rb_node_t * tail_node = *(lv_rb_node_t **)tail; - void * search_key = tail_node->data; - - lv_lru_rb_drop(lru, search_key, user_data); - } - - /*cache miss*/ - lv_rb_node_t * new_node = alloc_new_node(lru, (void *)key, user_data); - if(new_node == NULL) { - return NULL; - } - - lru->size++; - return new_node->data; -} - -void lv_lru_rb_drop(lv_lru_rb_t * lru, const void * key, void * user_data) -{ - LV_ASSERT_NULL(lru); - LV_ASSERT_NULL(key); - - if(lru == NULL || key == NULL) { - return; - } - - lv_rb_node_t * node = lv_rb_find(&lru->rb, key); - if(node == NULL) { - return; - } - - lru->free_cb(node->data, user_data); - - void * lru_node = *get_lru_node(lru, node); - lv_rb_drop_node(&lru->rb, node); - _lv_ll_remove(&lru->lru_ll, lru_node); - - lv_free(lru_node); - - lru->size--; -} - -void lv_lru_rb_drop_all(lv_lru_rb_t * lru, void * user_data) -{ - LV_ASSERT_NULL(lru); - - if(lru == NULL) { - return; - } - - lv_rb_node_t ** node; - _LV_LL_READ(&lru->lru_ll, node) { - /*free user handled data and do other clean up*/ - lru->free_cb((*node)->data, user_data); - } - - lv_rb_destroy(&lru->rb); - _lv_ll_clear(&lru->lru_ll); - - lru->size = 0; -} - -void lv_lru_rb_set_max_size(lv_lru_rb_t * lru, size_t max_size, void * user_data) -{ - LV_UNUSED(user_data); - lru->max_size = max_size; -} - -size_t lv_lru_rb_get_max_size(lv_lru_rb_t * lru, void * user_data) -{ - LV_UNUSED(user_data); - return lru->max_size; -} - -size_t lv_lru_rb_get_size(lv_lru_rb_t * lru, void * user_data) -{ - LV_UNUSED(user_data); - return lru->size; -} - -size_t lv_lru_rb_get_free_size(lv_lru_rb_t * lru, void * user_data) -{ - return lv_lru_rb_get_max_size(lru, user_data) - lv_lru_rb_get_size(lru, user_data); -} - -void lv_lru_rb_set_compare_cb(lv_lru_rb_t * lru, lv_lru_rb_compare_cb_t compare_cb, void * user_data) -{ - LV_UNUSED(user_data); - lru->rb.compare = (lv_rb_compare_t)compare_cb; -} - -void lv_lru_rb_set_create_cb(lv_lru_rb_t * lru, lv_lru_rb_create_cb_t create_cb, void * user_data) -{ - LV_UNUSED(user_data); - lru->create_cb = create_cb; -} - -void lv_lru_rb_set_free_cb(lv_lru_rb_t * lru, lv_lru_rb_free_cb_t free_cb, void * user_data) -{ - LV_UNUSED(user_data); - lru->free_cb = free_cb; -} - -/********************** - * STATIC FUNCTIONS - **********************/ -static void * alloc_new_node(lv_lru_rb_t * lru, void * key, void * user_data) -{ - LV_ASSERT_NULL(lru); - LV_ASSERT_NULL(key); - - if(lru == NULL || key == NULL) { - return NULL; - } - - lv_rb_node_t * node = lv_rb_insert(&lru->rb, key); - if(node == NULL) - goto FAILED_HANDLER3; - - lv_memcpy(node->data, key, lru->rb.size - sizeof(void *)); - - bool alloc_res = lru->create_cb(node->data, user_data); - if(alloc_res == false) - goto FAILED_HANDLER2; - - void * lru_node = _lv_ll_ins_head(&lru->lru_ll); - if(lru_node == NULL) - goto FAILED_HANDLER1; - - lv_memcpy(lru_node, &node, sizeof(void *)); - lv_memcpy(get_lru_node(lru, node), &lru_node, sizeof(void *)); - goto FAILED_HANDLER3; - -FAILED_HANDLER1: - lru->free_cb(node->data, user_data); -FAILED_HANDLER2: - lv_rb_drop_node(&lru->rb, node); - node = NULL; -FAILED_HANDLER3: - return node; -} - -inline static void ** get_lru_node(lv_lru_rb_t * lru, lv_rb_node_t * node) -{ - return (void **)((char *)node->data + lru->rb.size - sizeof(void *)); -} diff --git a/src/misc/lv_lru_rb.h b/src/misc/lv_lru_rb.h deleted file mode 100755 index 1f0ad64ff7..0000000000 --- a/src/misc/lv_lru_rb.h +++ /dev/null @@ -1,64 +0,0 @@ -/** - * @file lv_lru_rb.h - * - */ - -#ifndef LV_LRU_RB_H -#define LV_LRU_RB_H - -#ifdef __cplusplus -extern "C" { -#endif - -/********************* - * INCLUDES - *********************/ -#include "lv_types.h" - -#include "stdbool.h" -#include "lv_assert.h" - -/********************* - * DEFINES - *********************/ - -/********************** - * TYPEDEFS - **********************/ -struct _lv_lru_rb_t; -typedef struct _lv_lru_rb_t lv_lru_rb_t; - -typedef int8_t lv_lru_rb_compare_res_t; -typedef bool (*lv_lru_rb_create_cb_t)(void * node, void * user_data); -typedef void (*lv_lru_rb_free_cb_t)(void * node, void * user_data); -typedef lv_lru_rb_compare_res_t (*lv_lru_rb_compare_cb_t)(const void * a, const void * b); - -/********************** - * GLOBAL PROTOTYPES - **********************/ -lv_lru_rb_t * lv_lru_rb_create(size_t node_size, size_t max_size, lv_lru_rb_compare_cb_t compare_cb, - lv_lru_rb_create_cb_t create_cb, lv_lru_rb_free_cb_t free_cb); -void lv_lru_rb_destroy(lv_lru_rb_t * lru, void * user_data); -void * lv_lru_rb_get_or_create(lv_lru_rb_t * lru, const void * key, void * user_data); -void lv_lru_rb_drop(lv_lru_rb_t * lru, const void * key, void * user_data); -void lv_lru_rb_drop_all(lv_lru_rb_t * lru, void * user_data); -void lv_lru_rb_set_max_size(lv_lru_rb_t * lru, size_t max_size, void * user_data); -size_t lv_lru_rb_get_max_size(lv_lru_rb_t * lru, void * user_data); -size_t lv_lru_rb_get_size(lv_lru_rb_t * lru, void * user_data); -size_t lv_lru_rb_get_free_size(lv_lru_rb_t * lru, void * user_data); -void lv_lru_rb_set_compare_cb(lv_lru_rb_t * lru, lv_lru_rb_compare_cb_t compare_cb, void * user_data); -void lv_lru_rb_set_create_cb(lv_lru_rb_t * lru, lv_lru_rb_create_cb_t create_cb, void * user_data); -void lv_lru_rb_set_free_cb(lv_lru_rb_t * lru, lv_lru_rb_free_cb_t free_cb, void * user_data); -/************************* - * GLOBAL VARIABLES - *************************/ - -/********************** - * MACROS - **********************/ - -#ifdef __cplusplus -} /*extern "C"*/ -#endif - -#endif /*LV_LRU_RB_H*/ diff --git a/src/misc/lv_rb.c b/src/misc/lv_rb.c index 93c8e20cc0..b53ee6ae21 100755 --- a/src/misc/lv_rb.c +++ b/src/misc/lv_rb.c @@ -287,6 +287,7 @@ void lv_rb_destroy(lv_rb_t * tree) node = parent; } } + tree->root = NULL; } lv_rb_node_t * lv_rb_minimum(lv_rb_t * tree) diff --git a/src/widgets/canvas/lv_canvas.c b/src/widgets/canvas/lv_canvas.c index b5611833e0..5d02045ba2 100644 --- a/src/widgets/canvas/lv_canvas.c +++ b/src/widgets/canvas/lv_canvas.c @@ -15,7 +15,7 @@ #include "../../display/lv_display.h" #include "../../draw/sw/lv_draw_sw.h" #include "../../stdlib/lv_string.h" - +#include "../../misc/cache/lv_cache.h" /********************* * DEFINES *********************/ @@ -79,12 +79,11 @@ void lv_canvas_set_buffer(lv_obj_t * obj, void * buf, int32_t w, int32_t h, lv_c const void * src = lv_image_get_src(obj); if(src) { - lv_cache_lock(); - lv_cache_invalidate_by_src(src, LV_CACHE_SRC_TYPE_POINTER); - lv_cache_unlock(); + lv_image_cache_drop(src); } lv_image_set_src(obj, canvas->draw_buf); + lv_image_cache_drop(canvas->draw_buf); } void lv_canvas_set_draw_buf(lv_obj_t * obj, lv_draw_buf_t * draw_buf) @@ -97,12 +96,11 @@ void lv_canvas_set_draw_buf(lv_obj_t * obj, lv_draw_buf_t * draw_buf) const void * src = lv_image_get_src(obj); if(src) { - lv_cache_lock(); - lv_cache_invalidate_by_src(src, LV_CACHE_SRC_TYPE_POINTER); - lv_cache_unlock(); + lv_image_cache_drop(src); } lv_image_set_src(obj, draw_buf); + lv_image_cache_drop(draw_buf); } void lv_canvas_set_px(lv_obj_t * obj, int32_t x, int32_t y, lv_color_t color, lv_opa_t opa) @@ -385,9 +383,7 @@ static void lv_canvas_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj) lv_canvas_t * canvas = (lv_canvas_t *)obj; if(canvas->draw_buf == NULL) return; - lv_cache_lock(); - lv_cache_invalidate_by_src(canvas->draw_buf, LV_CACHE_SRC_TYPE_POINTER); - lv_cache_unlock(); + lv_image_cache_drop(&canvas->draw_buf); } #endif diff --git a/tests/ref_imgs/libs/tiny_ttf_1.png b/tests/ref_imgs/libs/tiny_ttf_1.png index 9cccd38181..c4ec1a0d26 100644 Binary files a/tests/ref_imgs/libs/tiny_ttf_1.png and b/tests/ref_imgs/libs/tiny_ttf_1.png differ diff --git a/tests/src/lv_test_conf_full.h b/tests/src/lv_test_conf_full.h index b7db43973c..188df05520 100644 --- a/tests/src/lv_test_conf_full.h +++ b/tests/src/lv_test_conf_full.h @@ -1,6 +1,5 @@ #define LV_MEM_SIZE (32 * 1024 * 1024) #define LV_SHADOW_CACHE_SIZE (8 * 1024) -#define LV_IMAGE_CACHE_DEF_SIZE 32 #define LV_USE_LOG 1 #define LV_LOG_LEVEL LV_LOG_LEVEL_TRACE #define LV_LOG_PRINTF 1 @@ -97,3 +96,5 @@ #define LV_USE_OBJ_ID_BUILTIN 1 #define LV_USE_OBJ_PROPERTY 1 #define LV_BIN_DECODER_RAM_LOAD 1 + +#define LV_CACHE_DEF_SIZE (10 * 1024 * 1024) diff --git a/tests/src/lv_test_conf_minimal.h b/tests/src/lv_test_conf_minimal.h index 42ad885220..5896c5ba34 100644 --- a/tests/src/lv_test_conf_minimal.h +++ b/tests/src/lv_test_conf_minimal.h @@ -12,8 +12,8 @@ #define LV_BUILD_EXAMPLES 1 -#define LV_USE_THEME_SIMPLE 1 -#define LV_USE_THEME_DEFAULT 0 +#define LV_USE_THEME_SIMPLE 1 +#define LV_USE_THEME_DEFAULT 0 #define LV_USE_LODEPNG 1 #define LV_USE_BMP 1 diff --git a/tests/src/test_cases/cache/test_cache.c b/tests/src/test_cases/cache/test_cache.c new file mode 100644 index 0000000000..d54ee3b6db --- /dev/null +++ b/tests/src/test_cases/cache/test_cache.c @@ -0,0 +1,152 @@ +#if LV_BUILD_TEST + +#include "../lvgl.h" +#include "lv_test_helpers.h" + +#include "unity/unity.h" + +static uint32_t MEM_SIZE = 0; + +// Cache size in bytes +#define CACHE_SIZE_BYTES 1000 + +lv_cache_t * cache; + +typedef struct _test_data { + lv_cache_slot_size_t slot; + + int32_t key1; + int32_t key2; + + void * data; // malloced data +} test_data; + +static lv_cache_compare_res_t compare_cb(const test_data * lhs, const test_data * rhs) +{ + if(lhs->key1 != rhs->key1) { + return lhs->key1 > rhs->key1 ? 1 : -1; + } + if(lhs->key2 != rhs->key2) { + return lhs->key2 > rhs->key2 ? 1 : -1; + } + return 0; +} + +static void free_cb(test_data * node, void * user_data) +{ + lv_free(node->data); +} + +void setUp(void) +{ + /* Function run before every test */ + MEM_SIZE = lv_test_get_free_mem(); + + lv_cache_ops_t ops = { + .compare_cb = (lv_cache_compare_cb_t) compare_cb, + .create_cb = NULL, + .free_cb = (lv_cache_free_cb_t)free_cb, + }; + cache = lv_cache_create(&lv_cache_class_lru_rb_size, sizeof(test_data), CACHE_SIZE_BYTES, ops); +} + +void tearDown(void) +{ + /* Function run after every test */ + lv_cache_destroy(cache, NULL); + cache = NULL; + + TEST_ASSERT_MEM_LEAK_LESS_THAN(MEM_SIZE, 32); +} + +void test_cache_1(void) +{ + + void * record_data_ptr = NULL; + + // create many node unless cache is full + uint32_t curr_mem_size = 8; + uint32_t curr_total_mem_size = 0; + while(curr_total_mem_size < CACHE_SIZE_BYTES) { + test_data search_key = { + .slot.size = curr_mem_size, + + .key1 = (int32_t)curr_mem_size, + .key2 = (int32_t)curr_mem_size + 1 + }; + + // acquire cache first + lv_cache_entry_t * entry = lv_cache_acquire(cache, &search_key, NULL); + if(entry != NULL) { + continue; + } + + // if cache miss then add cache + entry = lv_cache_add(cache, &search_key, NULL); + TEST_ASSERT_NOT_NULL(entry); + + test_data * data = lv_cache_entry_get_data(entry); + TEST_ASSERT_NOT_NULL(data); + + data->data = lv_malloc(data->slot.size); + + // record data ptr when {key1 = 32, key2 = 33}. + if(search_key.key1 == 32 && search_key.key2 == 33) { + record_data_ptr = data->data; + } + + lv_cache_release(cache, entry, NULL); + + curr_total_mem_size += curr_mem_size; + curr_mem_size *= 2; + + TEST_PRINTF("cache free: %d, allocated: %d", lv_cache_get_free_size(cache, NULL), curr_mem_size); + } + + /* + * allocated = 8 + 16 + 32 + 64 + 128 + 256 - 8 - 16 + 512 = 992 + * free = 1000 - 992 = 8 + * The last node size should be 1024, but the cache's max size is 1000. So new entry will be allocated failed and + * the loop will break. + * */ + TEST_ASSERT_EQUAL(8, lv_cache_get_free_size(cache, NULL)); + + /* + * Search entry {key1 = 32, key2 = 33} + */ + test_data search_key32 = { + .key1 = 32, + .key2 = 33 + }; + lv_cache_entry_t * entry_key32 = lv_cache_acquire(cache, &search_key32, NULL); + + test_data * cached_data_key32 = lv_cache_entry_get_data(entry_key32); + TEST_ASSERT_EQUAL(record_data_ptr, cached_data_key32->data); + + /* + * Now drop the cache {key1 = 32, key2 = 33}. However, this entry is acquired once without release, so `drop` + * will not release the memory allocated by this entry. + */ + uint32_t mem_curr_free = lv_test_get_free_mem(); + lv_cache_drop(cache, &search_key32, NULL); + /* + * Though it doesn't release the data, the entry and other structure has been freed. + * lv_rb_note_t (4 ptr + 1 int32 may align to 8 bit on 64 bit machine) + lv_ll (2 ptr + node_size). + * Also, the def heap has some other aligned attributes. It'll also affect the final result. + */ + TEST_ASSERT_MEM_LEAK_LESS_THAN(mem_curr_free, + sizeof(lv_rb_node_t) + + sizeof(void *) + (sizeof(lv_ll_node_t *) + sizeof(lv_ll_node_t *)) + + 32); // the last 32 is an error in memory allocating + mem_curr_free = lv_test_get_free_mem(); + lv_cache_release(cache, entry_key32, NULL); + TEST_ASSERT_MEM_LEAK_LESS_THAN(mem_curr_free, + lv_cache_entry_get_size(sizeof(test_data)) + sizeof(void *) + + 32 + + 32); + + // Now the freed cache size should be 8 + 32 = 40 + TEST_ASSERT_EQUAL(40, lv_cache_get_free_size(cache, NULL)); +} + +#endif diff --git a/tests/src/test_cases/draw/test_draw_blend.c b/tests/src/test_cases/draw/test_draw_blend.c index 773c4be86f..7be4c4f862 100644 --- a/tests/src/test_cases/draw/test_draw_blend.c +++ b/tests/src/test_cases/draw/test_draw_blend.c @@ -114,6 +114,8 @@ void canvas_blend_test(lv_obj_t * canvas_large, lv_draw_image_dsc_t * img_dsc, lv_canvas_init_layer(canvas_large, &layer); lv_draw_image(&layer, img_dsc, &area); lv_canvas_finish_layer(canvas_large, &layer); + + lv_image_cache_drop(img); } static void canvas_draw(const char * name, lv_color_format_t large_render_cf) diff --git a/tests/src/test_cases/libs/test_lodepng.c b/tests/src/test_cases/libs/test_lodepng.c index 1b045095df..dae39b78b1 100644 --- a/tests/src/test_cases/libs/test_lodepng.c +++ b/tests/src/test_cases/libs/test_lodepng.c @@ -58,7 +58,7 @@ void test_lodepng_1(void) TEST_ASSERT_EQUAL_SCREENSHOT("libs/png_1.png"); - TEST_ASSERT_MEM_LEAK_LESS_THAN(mem_before, 32); + TEST_ASSERT_MEM_LEAK_LESS_THAN(mem_before, 40); /* Re-add libpng decoder */ lv_libpng_init();