feat(cache): new cache framework (#5049)
Co-authored-by: _VIFEXTech <vifextech@foxmail.com>
This commit is contained in:
@@ -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.
|
||||
|
||||
2
lvgl.h
2
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"
|
||||
|
||||
|
||||
@@ -17,8 +17,6 @@ extern "C" {
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "../misc/lv_cache.h"
|
||||
#include "../misc/lv_cache_builtin.h"
|
||||
#include "../draw/lv_draw.h"
|
||||
#if LV_USE_DRAW_SW
|
||||
#include "../draw/sw/lv_draw_sw.h"
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -14,8 +14,10 @@ extern "C" {
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "../lv_draw.h"
|
||||
|
||||
#if LV_USE_DRAW_SDL
|
||||
|
||||
#include <src/misc/cache/lv_cache.h>
|
||||
#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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/**********************
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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*/
|
||||
|
||||
@@ -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*/
|
||||
|
||||
@@ -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*/
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#include "lv_tiny_ttf.h"
|
||||
#if LV_USE_TINY_TTF
|
||||
#include <stdio.h>
|
||||
#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
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
404
src/misc/cache/_lv_cache_lru_rb.c
vendored
Normal file
404
src/misc/cache/_lv_cache_lru_rb.c
vendored
Normal file
@@ -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;
|
||||
}
|
||||
44
src/misc/cache/_lv_cache_lru_rb.h
vendored
Normal file
44
src/misc/cache/_lv_cache_lru_rb.h
vendored
Normal file
@@ -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*/
|
||||
213
src/misc/cache/lv_cache.c
vendored
Normal file
213
src/misc/cache/lv_cache.c
vendored
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
67
src/misc/cache/lv_cache.h
vendored
Normal file
67
src/misc/cache/lv_cache.h
vendored
Normal file
@@ -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 <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#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*/
|
||||
167
src/misc/cache/lv_cache_entry.c
vendored
Normal file
167
src/misc/cache/lv_cache_entry.c
vendored
Normal file
@@ -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
|
||||
**********************/
|
||||
55
src/misc/cache/lv_cache_entry.h
vendored
Normal file
55
src/misc/cache/lv_cache_entry.h
vendored
Normal file
@@ -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 <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
/*********************
|
||||
* 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*/
|
||||
51
src/misc/cache/lv_cache_entry_private.h
vendored
Normal file
51
src/misc/cache/lv_cache_entry_private.h
vendored
Normal file
@@ -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 <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#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*/
|
||||
114
src/misc/cache/lv_cache_private.h
vendored
Normal file
114
src/misc/cache/lv_cache_private.h
vendored
Normal file
@@ -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 <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#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*/
|
||||
59
src/misc/cache/lv_image_cache.c
vendored
Normal file
59
src/misc/cache/lv_image_cache.c
vendored
Normal file
@@ -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
|
||||
**********************/
|
||||
@@ -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*/
|
||||
@@ -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
|
||||
**********************/
|
||||
@@ -1,306 +0,0 @@
|
||||
/**
|
||||
* @file lv_cache.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_CACHE_H
|
||||
#define LV_CACHE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#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*/
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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 *));
|
||||
}
|
||||
@@ -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*/
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
152
tests/src/test_cases/cache/test_cache.c
vendored
Normal file
152
tests/src/test_cases/cache/test_cache.c
vendored
Normal file
@@ -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
|
||||
@@ -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)
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user