acid-drop- Hacking the planet from a LilyGo T-Deck using custom firmware |
git clone git://git.acid.vegas/acid-drop.git |
Log | Files | Refs | Archive | README | LICENSE |
lv_img_cache.c (6911B)
1 /** 2 * @file lv_img_cache.c 3 * 4 */ 5 6 /********************* 7 * INCLUDES 8 *********************/ 9 #include "../misc/lv_assert.h" 10 #include "lv_img_cache.h" 11 #include "lv_img_decoder.h" 12 #include "lv_draw_img.h" 13 #include "../hal/lv_hal_tick.h" 14 #include "../misc/lv_gc.h" 15 16 /********************* 17 * DEFINES 18 *********************/ 19 /*Decrement life with this value on every open*/ 20 #define LV_IMG_CACHE_AGING 1 21 22 /*Boost life by this factor (multiply time_to_open with this value)*/ 23 #define LV_IMG_CACHE_LIFE_GAIN 1 24 25 /*Don't let life to be greater than this limit because it would require a lot of time to 26 * "die" from very high values*/ 27 #define LV_IMG_CACHE_LIFE_LIMIT 1000 28 29 /********************** 30 * TYPEDEFS 31 **********************/ 32 33 /********************** 34 * STATIC PROTOTYPES 35 **********************/ 36 #if LV_IMG_CACHE_DEF_SIZE 37 static bool lv_img_cache_match(const void * src1, const void * src2); 38 #endif 39 40 /********************** 41 * STATIC VARIABLES 42 **********************/ 43 #if LV_IMG_CACHE_DEF_SIZE 44 static uint16_t entry_cnt; 45 #endif 46 47 /********************** 48 * MACROS 49 **********************/ 50 51 /********************** 52 * GLOBAL FUNCTIONS 53 **********************/ 54 55 /** 56 * Open an image using the image decoder interface and cache it. 57 * The image will be left open meaning if the image decoder open callback allocated memory then it will remain. 58 * The image is closed if a new image is opened and the new image takes its place in the cache. 59 * @param src source of the image. Path to file or pointer to an `lv_img_dsc_t` variable 60 * @param color color The color of the image with `LV_IMG_CF_ALPHA_...` 61 * @return pointer to the cache entry or NULL if can open the image 62 */ 63 _lv_img_cache_entry_t * _lv_img_cache_open(const void * src, lv_color_t color, int32_t frame_id) 64 { 65 /*Is the image cached?*/ 66 _lv_img_cache_entry_t * cached_src = NULL; 67 68 #if LV_IMG_CACHE_DEF_SIZE 69 if(entry_cnt == 0) { 70 LV_LOG_WARN("lv_img_cache_open: the cache size is 0"); 71 return NULL; 72 } 73 74 _lv_img_cache_entry_t * cache = LV_GC_ROOT(_lv_img_cache_array); 75 76 /*Decrement all lifes. Make the entries older*/ 77 uint16_t i; 78 for(i = 0; i < entry_cnt; i++) { 79 if(cache[i].life > INT32_MIN + LV_IMG_CACHE_AGING) { 80 cache[i].life -= LV_IMG_CACHE_AGING; 81 } 82 } 83 84 for(i = 0; i < entry_cnt; i++) { 85 if(color.full == cache[i].dec_dsc.color.full && 86 frame_id == cache[i].dec_dsc.frame_id && 87 lv_img_cache_match(src, cache[i].dec_dsc.src)) { 88 /*If opened increment its life. 89 *Image difficult to open should live longer to keep avoid frequent their recaching. 90 *Therefore increase `life` with `time_to_open`*/ 91 cached_src = &cache[i]; 92 cached_src->life += cached_src->dec_dsc.time_to_open * LV_IMG_CACHE_LIFE_GAIN; 93 if(cached_src->life > LV_IMG_CACHE_LIFE_LIMIT) cached_src->life = LV_IMG_CACHE_LIFE_LIMIT; 94 LV_LOG_TRACE("image source found in the cache"); 95 break; 96 } 97 } 98 99 /*The image is not cached then cache it now*/ 100 if(cached_src) return cached_src; 101 102 /*Find an entry to reuse. Select the entry with the least life*/ 103 cached_src = &cache[0]; 104 for(i = 1; i < entry_cnt; i++) { 105 if(cache[i].life < cached_src->life) { 106 cached_src = &cache[i]; 107 } 108 } 109 110 /*Close the decoder to reuse if it was opened (has a valid source)*/ 111 if(cached_src->dec_dsc.src) { 112 lv_img_decoder_close(&cached_src->dec_dsc); 113 LV_LOG_INFO("image draw: cache miss, close and reuse an entry"); 114 } 115 else { 116 LV_LOG_INFO("image draw: cache miss, cached to an empty entry"); 117 } 118 #else 119 cached_src = &LV_GC_ROOT(_lv_img_cache_single); 120 #endif 121 /*Open the image and measure the time to open*/ 122 uint32_t t_start = lv_tick_get(); 123 lv_res_t open_res = lv_img_decoder_open(&cached_src->dec_dsc, src, color, frame_id); 124 if(open_res == LV_RES_INV) { 125 LV_LOG_WARN("Image draw cannot open the image resource"); 126 lv_memset_00(cached_src, sizeof(_lv_img_cache_entry_t)); 127 cached_src->life = INT32_MIN; /*Make the empty entry very "weak" to force its us*/ 128 return NULL; 129 } 130 131 cached_src->life = 0; 132 133 /*If `time_to_open` was not set in the open function set it here*/ 134 if(cached_src->dec_dsc.time_to_open == 0) { 135 cached_src->dec_dsc.time_to_open = lv_tick_elaps(t_start); 136 } 137 138 if(cached_src->dec_dsc.time_to_open == 0) cached_src->dec_dsc.time_to_open = 1; 139 140 return cached_src; 141 } 142 143 /** 144 * Set the number of images to be cached. 145 * More cached images mean more opened image at same time which might mean more memory usage. 146 * E.g. if 20 PNG or JPG images are open in the RAM they consume memory while opened in the cache. 147 * @param new_entry_cnt number of image to cache 148 */ 149 void lv_img_cache_set_size(uint16_t new_entry_cnt) 150 { 151 #if LV_IMG_CACHE_DEF_SIZE == 0 152 LV_UNUSED(new_entry_cnt); 153 LV_LOG_WARN("Can't change cache size because it's disabled by LV_IMG_CACHE_DEF_SIZE = 0"); 154 #else 155 if(LV_GC_ROOT(_lv_img_cache_array) != NULL) { 156 /*Clean the cache before free it*/ 157 lv_img_cache_invalidate_src(NULL); 158 lv_mem_free(LV_GC_ROOT(_lv_img_cache_array)); 159 } 160 161 /*Reallocate the cache*/ 162 LV_GC_ROOT(_lv_img_cache_array) = lv_mem_alloc(sizeof(_lv_img_cache_entry_t) * new_entry_cnt); 163 LV_ASSERT_MALLOC(LV_GC_ROOT(_lv_img_cache_array)); 164 if(LV_GC_ROOT(_lv_img_cache_array) == NULL) { 165 entry_cnt = 0; 166 return; 167 } 168 entry_cnt = new_entry_cnt; 169 170 /*Clean the cache*/ 171 lv_memset_00(LV_GC_ROOT(_lv_img_cache_array), entry_cnt * sizeof(_lv_img_cache_entry_t)); 172 #endif 173 } 174 175 /** 176 * Invalidate an image source in the cache. 177 * Useful if the image source is updated therefore it needs to be cached again. 178 * @param src an image source path to a file or pointer to an `lv_img_dsc_t` variable. 179 */ 180 void lv_img_cache_invalidate_src(const void * src) 181 { 182 LV_UNUSED(src); 183 #if LV_IMG_CACHE_DEF_SIZE 184 _lv_img_cache_entry_t * cache = LV_GC_ROOT(_lv_img_cache_array); 185 186 uint16_t i; 187 for(i = 0; i < entry_cnt; i++) { 188 if(src == NULL || lv_img_cache_match(src, cache[i].dec_dsc.src)) { 189 if(cache[i].dec_dsc.src != NULL) { 190 lv_img_decoder_close(&cache[i].dec_dsc); 191 } 192 193 lv_memset_00(&cache[i], sizeof(_lv_img_cache_entry_t)); 194 } 195 } 196 #endif 197 } 198 199 /********************** 200 * STATIC FUNCTIONS 201 **********************/ 202 203 #if LV_IMG_CACHE_DEF_SIZE 204 static bool lv_img_cache_match(const void * src1, const void * src2) 205 { 206 lv_img_src_t src_type = lv_img_src_get_type(src1); 207 if(src_type == LV_IMG_SRC_VARIABLE) 208 return src1 == src2; 209 if(src_type != LV_IMG_SRC_FILE) 210 return false; 211 if(lv_img_src_get_type(src2) != LV_IMG_SRC_FILE) 212 return false; 213 return strcmp(src1, src2) == 0; 214 } 215 #endif