1 /**
2 * @file lv_image_cache.c
3 *
4  */
5 
6 /*********************
7  *      INCLUDES
8  *********************/
9 
10 #include "../../draw/lv_image_decoder_private.h"
11 #include "../lv_assert.h"
12 #include "../../core/lv_global.h"
13 #include "../../misc/lv_iter.h"
14 
15 #include "lv_image_cache.h"
16 #include "lv_image_header_cache.h"
17 
18 /*********************
19  *      DEFINES
20  *********************/
21 
22 #define CACHE_NAME  "IMAGE"
23 
24 #define img_cache_p (LV_GLOBAL_DEFAULT()->img_cache)
25 #define image_cache_draw_buf_handlers &(LV_GLOBAL_DEFAULT()->image_cache_draw_buf_handlers)
26 
27 /**********************
28  *      TYPEDEFS
29  **********************/
30 
31 /**********************
32  *  STATIC PROTOTYPES
33  **********************/
34 
35 static lv_cache_compare_res_t image_cache_compare_cb(const lv_image_cache_data_t * lhs,
36                                                      const lv_image_cache_data_t * rhs);
37 static void image_cache_free_cb(lv_image_cache_data_t * entry, void * user_data);
38 static void iter_inspect_cb(void * elem);
39 
40 /**********************
41  *  GLOBAL VARIABLES
42  **********************/
43 
44 /**********************
45  *  STATIC VARIABLES
46  **********************/
47 
48 /**********************
49  *      MACROS
50  **********************/
51 
52 /**********************
53  *   GLOBAL FUNCTIONS
54  **********************/
55 
lv_image_cache_init(uint32_t size)56 lv_result_t lv_image_cache_init(uint32_t size)
57 {
58     if(img_cache_p != NULL) {
59         return LV_RESULT_OK;
60     }
61 
62     img_cache_p = lv_cache_create(&lv_cache_class_lru_rb_size,
63     sizeof(lv_image_cache_data_t), size, (lv_cache_ops_t) {
64         .compare_cb = (lv_cache_compare_cb_t) image_cache_compare_cb,
65         .create_cb = NULL,
66         .free_cb = (lv_cache_free_cb_t) image_cache_free_cb,
67     });
68 
69     lv_cache_set_name(img_cache_p, CACHE_NAME);
70     return img_cache_p != NULL ? LV_RESULT_OK : LV_RESULT_INVALID;
71 }
72 
lv_image_cache_resize(uint32_t new_size,bool evict_now)73 void lv_image_cache_resize(uint32_t new_size, bool evict_now)
74 {
75     lv_cache_set_max_size(img_cache_p, new_size, NULL);
76     if(evict_now) {
77         lv_cache_reserve(img_cache_p, new_size, NULL);
78     }
79 }
80 
lv_image_cache_drop(const void * src)81 void lv_image_cache_drop(const void * src)
82 {
83     /*If user invalidate image, the header cache should be invalidated too.*/
84     lv_image_header_cache_drop(src);
85 
86     if(src == NULL) {
87         lv_cache_drop_all(img_cache_p, NULL);
88         return;
89     }
90 
91     lv_image_cache_data_t search_key = {
92         .src = src,
93         .src_type = lv_image_src_get_type(src),
94     };
95 
96     lv_cache_drop(img_cache_p, &search_key, NULL);
97 }
98 
lv_image_cache_is_enabled(void)99 bool lv_image_cache_is_enabled(void)
100 {
101     return lv_cache_is_enabled(img_cache_p);
102 }
103 
lv_image_cache_iter_create(void)104 lv_iter_t * lv_image_cache_iter_create(void)
105 {
106     return lv_cache_iter_create(img_cache_p);
107 }
108 
lv_image_cache_dump(void)109 void lv_image_cache_dump(void)
110 {
111     lv_iter_t * iter = lv_image_cache_iter_create();
112     if(iter == NULL) return;
113 
114     LV_LOG_USER("Image cache dump:");
115     LV_LOG_USER("\tsize\tdata_size\tcf\trc\ttype\tdecoded\t\t\tsrc");
116     lv_iter_inspect(iter, iter_inspect_cb);
117 }
118 
119 /**********************
120  *   STATIC FUNCTIONS
121  **********************/
122 
image_cache_common_compare(const void * lhs_src,lv_image_src_t lhs_src_type,const void * rhs_src,lv_image_src_t rhs_src_type)123 inline static lv_cache_compare_res_t image_cache_common_compare(const void * lhs_src, lv_image_src_t lhs_src_type,
124                                                                 const void * rhs_src, lv_image_src_t rhs_src_type)
125 {
126     if(lhs_src_type == rhs_src_type) {
127         if(lhs_src_type == LV_IMAGE_SRC_FILE) {
128             int32_t cmp_res = lv_strcmp(lhs_src, rhs_src);
129             if(cmp_res != 0) {
130                 return cmp_res > 0 ? 1 : -1;
131             }
132         }
133         else if(lhs_src_type == LV_IMAGE_SRC_VARIABLE) {
134             if(lhs_src != rhs_src) {
135                 return lhs_src > rhs_src ? 1 : -1;
136             }
137         }
138         return 0;
139     }
140     return lhs_src_type > rhs_src_type ? 1 : -1;
141 }
142 
image_cache_compare_cb(const lv_image_cache_data_t * lhs,const lv_image_cache_data_t * rhs)143 static lv_cache_compare_res_t image_cache_compare_cb(
144     const lv_image_cache_data_t * lhs,
145     const lv_image_cache_data_t * rhs)
146 {
147     return image_cache_common_compare(lhs->src, lhs->src_type, rhs->src, rhs->src_type);
148 }
149 
image_cache_free_cb(lv_image_cache_data_t * entry,void * user_data)150 static void image_cache_free_cb(lv_image_cache_data_t * entry, void * user_data)
151 {
152     LV_UNUSED(user_data);
153 
154     /* Destroy the decoded draw buffer if necessary. */
155     lv_draw_buf_t * decoded = (lv_draw_buf_t *)entry->decoded;
156     if(lv_draw_buf_has_flag(decoded, LV_IMAGE_FLAGS_ALLOCATED)) {
157         lv_draw_buf_destroy(decoded);
158     }
159 
160     /*Free the duplicated file name*/
161     if(entry->src_type == LV_IMAGE_SRC_FILE) lv_free((void *)entry->src);
162 }
163 
iter_inspect_cb(void * elem)164 static void iter_inspect_cb(void * elem)
165 {
166     lv_image_cache_data_t * data = (lv_image_cache_data_t *)elem;
167     lv_draw_buf_t * decoded = (lv_draw_buf_t *)data->decoded;
168     lv_image_header_t * header = &decoded->header;
169     lv_cache_entry_t * entry = lv_cache_entry_get_entry(data, img_cache_p->node_size);
170 
171     LV_UNUSED(decoded);
172     LV_UNUSED(header);
173     LV_UNUSED(entry);
174 
175     /*  size    data_size   cf  rc  type    decoded         src*/
176 #define IMAGE_CACHE_DUMP_FORMAT "	%4dx%-4d	%9"LV_PRIu32"	%d	%"LV_PRId32"	"
177     switch(data->src_type) {
178         case LV_IMAGE_SRC_FILE:
179             LV_LOG_USER(IMAGE_CACHE_DUMP_FORMAT "file\t%-12p\t%s", header->w, header->h, decoded->data_size, header->cf,
180                         lv_cache_entry_get_ref(entry), (void *)data->decoded, (char *)data->src);
181             break;
182         case LV_IMAGE_SRC_VARIABLE:
183             LV_LOG_USER(IMAGE_CACHE_DUMP_FORMAT "var \t%-12p\t%p", header->w, header->h, decoded->data_size, header->cf,
184                         lv_cache_entry_get_ref(entry), (void *)data->decoded, data->src);
185             break;
186         default:
187             LV_LOG_USER(IMAGE_CACHE_DUMP_FORMAT "unkn\t%-12p\t%p", header->w, header->h, decoded->data_size, header->cf,
188                         lv_cache_entry_get_ref(entry), (void *)data->decoded, data->src);
189             break;
190     }
191 }
192