feat(image_decoder): add image decoder header cache (#5420)

This commit is contained in:
Benign X 2024-01-22 21:28:58 +08:00 committed by GitHub
parent 4a60e01f8c
commit 7b68aef4ab
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 142 additions and 17 deletions

View File

@ -271,6 +271,10 @@
*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
/*Default number of image header cache entries. The cache is used to store the headers of images
*The main logic is like `LV_CACHE_DEF_SIZE` but for image headers.*/
#define LV_IMAGE_HEADER_CACHE_DEF_CNT 0
/*Number of stops allowed per gradient. Increase this to allow more stops.
*This adds (sizeof(lv_color_t) + 1) bytes per additional stop*/
#define LV_GRADIENT_MAX_STOPS 2

12
Kconfig
View File

@ -269,6 +269,18 @@ menu "LVGL configuration"
save the continuous open/decode of images.
However the opened images might consume additional RAM.
config LV_IMAGE_HEADER_CACHE_DEF_CNT
int "Default image header cache count. 0 to disable caching."
default 0
depends on LV_USE_DRAW_SW
help
If only the built-in image formats are used there is no real advantage of caching.
(I.e. no new image decoder is added).
With complex image decoders (e.g. PNG or JPG) caching can
save the continuous getting header information of images.
However the records of opened images headers might consume additional RAM.
config LV_GRADIENT_MAX_STOPS
int "Number of stops allowed per gradient."
default 2

View File

@ -261,6 +261,10 @@
*will be dropped immediately after usage.*/
#define LV_CACHE_DEF_SIZE 0
/*Default number of image header cache entries. The cache is used to store the headers of images
*The main logic is like `LV_CACHE_DEF_SIZE` but for image headers.*/
#define LV_IMAGE_HEADER_CACHE_DEF_CNT 0
/*Number of stops allowed per gradient. Increase this to allow more stops.
*This adds (sizeof(lv_color_t) + 1) bytes per additional stop*/
#define LV_GRADIENT_MAX_STOPS 2

View File

@ -271,6 +271,10 @@
*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
/*Default number of image header cache entries. The cache is used to store the headers of images
*The main logic is like `LV_CACHE_DEF_SIZE` but for image headers.*/
#define LV_IMAGE_HEADER_CACHE_DEF_CNT 0
/*Number of stops allowed per gradient. Increase this to allow more stops.
*This adds (sizeof(lv_color_t) + 1) bytes per additional stop*/
#define LV_GRADIENT_MAX_STOPS 2

View File

@ -101,6 +101,10 @@ typedef struct _lv_global_t {
lv_cache_t * img_cache;
#endif
#if LV_IMAGE_HEADER_CACHE_DEF_CNT > 0
lv_cache_t * img_header_cache;
#endif
lv_draw_global_info_t draw_info;
#if defined(LV_DRAW_SW_SHADOW_CACHE_SIZE) && LV_DRAW_SW_SHADOW_CACHE_SIZE > 0
lv_draw_sw_shadow_cache_t sw_shadow_cache;

View File

@ -18,6 +18,7 @@
*********************/
#define img_decoder_ll_p &(LV_GLOBAL_DEFAULT()->img_decoder_ll)
#define img_cache_p (LV_GLOBAL_DEFAULT()->img_cache)
#define img_header_cache_p (LV_GLOBAL_DEFAULT()->img_header_cache)
/**********************
* TYPEDEFS
@ -37,6 +38,12 @@ static uint32_t img_width_to_stride(lv_image_header_t * header);
*/
static lv_image_decoder_t * image_decoder_get_info(const void * src, lv_image_header_t * header);
#if LV_IMAGE_HEADER_CACHE_DEF_CNT > 0
static lv_cache_compare_res_t image_decoder_header_cache_compare_cb(const lv_image_header_cache_data_t * lhs,
const lv_image_header_cache_data_t * rhs);
static void image_decoder_header_cache_free_cb(lv_image_header_cache_data_t * entry, void * user_data);
#endif
#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);
@ -70,6 +77,16 @@ void _lv_image_decoder_init(void)
.create_cb = NULL,
.free_cb = (lv_cache_free_cb_t)image_decoder_cache_free_cb,
});
#endif
#if LV_IMAGE_HEADER_CACHE_DEF_CNT > 0
img_header_cache_p = lv_cache_create(&lv_cache_class_lru_rb_count,
sizeof(lv_image_header_cache_data_t), LV_IMAGE_HEADER_CACHE_DEF_CNT, (lv_cache_ops_t) {
.compare_cb = (lv_cache_compare_cb_t)image_decoder_header_cache_compare_cb,
.create_cb = NULL,
.free_cb = (lv_cache_free_cb_t)image_decoder_header_cache_free_cb
});
#endif
}
@ -81,6 +98,10 @@ void _lv_image_decoder_deinit(void)
#if LV_CACHE_DEF_SIZE > 0
lv_cache_destroy(img_cache_p, NULL);
#endif
#if LV_IMAGE_HEADER_CACHE_DEF_CNT > 0
lv_cache_destroy(img_header_cache_p, NULL);
#endif
_lv_ll_clear(img_decoder_ll_p);
}
@ -295,17 +316,51 @@ static lv_image_decoder_t * image_decoder_get_info(const void * src, lv_image_he
}
lv_image_decoder_t * decoder;
#if LV_IMAGE_HEADER_CACHE_DEF_CNT > 0
lv_image_header_cache_data_t search_key;
search_key.src_type = src_type;
search_key.src = src;
lv_cache_entry_t * entry = lv_cache_acquire(img_header_cache_p, &search_key, NULL);
if(entry) {
lv_image_header_cache_data_t * cached_data = lv_cache_entry_get_data(entry);
*header = cached_data->header;
decoder = cached_data->decoder;
lv_cache_release(img_header_cache_p, entry, NULL);
return decoder;
}
#endif
_LV_LL_READ(img_decoder_ll_p, decoder) {
/*Info and Open callbacks are required*/
if(decoder->info_cb && decoder->open_cb) {
lv_result_t res = decoder->info_cb(decoder, src, header);
if(res == LV_RESULT_OK) {
if(header->stride == 0) header->stride = img_width_to_stride(header);
return decoder;
break;
}
}
}
return NULL;
#if LV_IMAGE_HEADER_CACHE_DEF_CNT > 0
if(decoder) {
if(src_type == LV_IMAGE_SRC_FILE) search_key.src = lv_strdup(src);
search_key.decoder = decoder;
search_key.header = *header;
entry = lv_cache_add(img_header_cache_p, &search_key, NULL);
if(entry == NULL) {
if(src_type == LV_IMAGE_SRC_FILE) lv_free((void *)search_key.src);
return NULL;
}
lv_cache_release(img_header_cache_p, entry, NULL);
}
#endif
return decoder;
}
static uint32_t img_width_to_stride(lv_image_header_t * header)
@ -318,26 +373,50 @@ static uint32_t img_width_to_stride(lv_image_header_t * header)
}
}
#if LV_CACHE_DEF_SIZE > 0 || LV_IMAGE_HEADER_CACHE_DEF_CNT > 0
inline static lv_cache_compare_res_t image_decoder_common_compare(const void * lhs_src, lv_image_src_t lhs_src_type,
const void * rhs_src, lv_image_src_t rhs_src_type)
{
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;
}
#endif
#if LV_IMAGE_HEADER_CACHE_DEF_CNT > 0
static lv_cache_compare_res_t image_decoder_header_cache_compare_cb(
const lv_image_header_cache_data_t * lhs,
const lv_image_header_cache_data_t * rhs)
{
return image_decoder_common_compare(lhs->src, lhs->src_type, rhs->src, rhs->src_type);
}
static void image_decoder_header_cache_free_cb(lv_image_header_cache_data_t * entry, void * user_data)
{
LV_UNUSED(user_data); /*Unused*/
if(entry->src_type == LV_IMAGE_SRC_FILE) lv_free((void *)entry->src);
}
#endif
#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;
return image_decoder_common_compare(lhs->src, lhs->src_type, rhs->src, rhs->src_type);
}
static void image_decoder_cache_free_cb(lv_image_cache_data_t * entry, void * user_data)

View File

@ -125,6 +125,14 @@ typedef struct _lv_image_decoder_cache_data_t {
void * user_data;
} lv_image_cache_data_t;
typedef struct _lv_image_decoder_header_cache_data_t {
const void * src;
lv_image_src_t src_type;
lv_image_header_t header;
lv_image_decoder_t * decoder;
} lv_image_header_cache_data_t;
/**Describe an image decoding session. Stores data about the decoding*/
struct _lv_image_decoder_dsc_t {
/**The decoder which was able to open the image source*/

View File

@ -771,6 +771,16 @@
#endif
#endif
/*Default number of image header cache entries. The cache is used to store the headers of images
*The main logic is like `LV_CACHE_DEF_SIZE` but for image headers.*/
#ifndef LV_IMAGE_HEADER_CACHE_DEF_CNT
#ifdef CONFIG_LV_IMAGE_HEADER_CACHE_DEF_CNT
#define LV_IMAGE_HEADER_CACHE_DEF_CNT CONFIG_LV_IMAGE_HEADER_CACHE_DEF_CNT
#else
#define LV_IMAGE_HEADER_CACHE_DEF_CNT 0
#endif
#endif
/*Number of stops allowed per gradient. Increase this to allow more stops.
*This adds (sizeof(lv_color_t) + 1) bytes per additional stop*/
#ifndef LV_GRADIENT_MAX_STOPS